summaryrefslogtreecommitdiff
path: root/Master
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2011-10-10 21:53:20 +0000
committerKarl Berry <karl@freefriends.org>2011-10-10 21:53:20 +0000
commit8fdc0d5c9ee743261c162302bdafbb83f9cfb542 (patch)
tree05e2062f23f57880ed2e0a26ad898e81b9d813be /Master
parentd2d088ff389655c2c3aad324760138895af2a9d3 (diff)
l3experimental 2900 (10oct11)
git-svn-id: svn://tug.org/texlive/trunk@24258 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/README23
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdfbin0 -> 640244 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdfbin0 -> 628821 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-test.tex380
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-tschichold-example-keyval.tex281
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-tschichold-example.tex185
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdfbin478394 -> 478180 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdfbin0 -> 622455 bytes
-rw-r--r--Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdfbin0 -> 570935 bytes
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx3545
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx1966
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins43
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx12
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx2140
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx1602
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.ins41
-rw-r--r--Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty1637
-rw-r--r--Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty1637
-rw-r--r--Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty970
-rw-r--r--Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty2
-rw-r--r--Master/texmf-dist/tex/latex/l3experimental/xgalley/l3galley.sty764
-rw-r--r--Master/texmf-dist/tex/latex/l3experimental/xgalley/xgalley.sty616
22 files changed, 14982 insertions, 862 deletions
diff --git a/Master/texmf-dist/doc/latex/l3experimental/README b/Master/texmf-dist/doc/latex/l3experimental/README
index 83c8236aeba..9acac689ec6 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/README
+++ b/Master/texmf-dist/doc/latex/l3experimental/README
@@ -28,7 +28,21 @@ are under active development and the interfaces may change.
Currently included in the CTAN release of l3experimental are the following
bundles:
+ * l3str
* xcoffins
+ * xgalley
+
+l3str
+-----
+
+A 'string' in TeX terms is a token list in which all of the tokens have
+category code 12 ('other'), with the exception of spaces which have the
+category code 10 ('space'). The l3str bundle consists of two parts. The
+first is l3str itself. This is a collection of functions to act on strings,
+including for manipulations such as UTF8 mappings in pdfTeX. The second
+part of the bundle is l3regex, a regular expression search-and-replace
+implementation written in TeX primitives. The regex module works on a string
+basis, ignoring category codes.
xcoffins
--------
@@ -51,15 +65,6 @@ there are ways to control or change its behaviour. The xgalley module
provides a mechanism for filling galleys and controlling the spacing,
hyphenation and justification within them.
-xfss
-----
-
-This package is a translation of LaTeX's font selection scheme into expl3.
-Its primary utility is to provide font support when LaTeX3 is built as a
-format, but in time features will be added that will make it useful in 2e
-as well.
-
-
DISCUSSION
----------
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf
new file mode 100644
index 00000000000..9ee837a7c92
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3regex.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdf b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdf
new file mode 100644
index 00000000000..f4b06528802
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/l3experimental/l3str/l3str.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-test.tex b/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-test.tex
deleted file mode 100644
index 1ede1770c08..00000000000
--- a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-test.tex
+++ /dev/null
@@ -1,380 +0,0 @@
-
-\documentclass{article}
-
-\usepackage[T1]{fontenc}
-\usepackage{times,multicol}
-\usepackage{xcoffins}
-
-\usepackage{color}
-\newcommand\cbox[2][.8]{{\setlength\fboxsep{0pt}\colorbox[gray]{#1}{#2}}}
-
-\newcommand\hrulebox [2]{\setbox#1\hbox to#2{{\scriptsize\itshape
- \color{blue}\hrulefill #2\hrulefill}}}
-\newcommand\vrulebox [2]{\setbox#1\vbox to#2{{\hsize 1pt\centering\scriptsize
- \itshape\color{blue}\leaders\vrule\vfill
- \hbox to0pt{\hss #2\hss}\leaders\vrule\vfill\par}}}
-
-
-\addtolength\textwidth{10pt}
-
-\showboxdepth 9999
-\showboxbreadth 9999
-\tracingonline 1
-
-
-\scrollmode
-
-\newbox\zzz
-
-
-\begin{document}
-
-
-\title{Test file for coffins}
-\author{FMi}
-\maketitle
-
-First we add a few test coffins:
-\begin{verbatim}
- \newcoffin \aaa
- \newcoffin \bbb
- \newcoffin \ccc
- \newcoffin \ddd
-\end{verbatim}
- \newcoffin \aaa
- \newcoffin \bbb
- \newcoffin \ccc
- \newcoffin \ddd
-and some boxes not set up as ordinary boxes (without extra poles):
-\begin{verbatim}
- \newbox \xxx
- \newbox \yyy
-\end{verbatim}
- \newbox \xxx
- \newbox \yyy
-
-
-If a coffin receives data a set of ``natural'' default poles are automatically added.
-\begin{verbatim}
-\sbox\aaa{\fbox{\begin{tabular}[b]{l}123\\4\\5\end{tabular}}}
-\showcoffindata \aaa
-\end{verbatim}
-\sbox\aaa{\fbox{\begin{tabular}[b]{l}123\\4\\5\end{tabular}}}
-\showcoffindata \aaa
-
-
-In contrast, boxes not declared as coffins have no poles defined. However, if
-used as coffins at least the natural default poles can be used without
-further problems, i.e.,they are changed to coffins automatically on use.
-\begin{verbatim}
-\sbox\xxx{\fbox{Some very looooonggg Caption Text}}
-\showpoles \xxx
-\end{verbatim}
-\sbox\xxx{\fbox{Some very looooonggg Caption Text}}
-\showcoffindata \xxx
-
-
-Using \verb|\setvcoffin| instead of \verb|\sbox| gives us the codes with
-\texttt{T} and \texttt{B}. Similar to \verb|\parbox| this command requires to
-specify a target width of the box:
-\begin{verbatim}
-\setvcoffin \aaa {1.5cm} {\centering
- \fbox{\begin{tabular}[b]{l}123\\4\\5\end{tabular}}}
-\showcoffindata \aaa
-\end{verbatim}
-\setvcoffin \aaa {1.5cm} {\centering
- \fbox{\begin{tabular}[b]{l}123\\4\\5\end{tabular}}}
-\showcoffindata \aaa
-
-There are a dozen natural poles per box (some with multiple names); you can
-move each of the poles to someplace else (either to an absolute position in
-``box space'' or relative to its previous position). The coordinates can
-refer to box dimensions (using \verb|\height|, \verb|\depth|,
- and \verb|width|). First we move some pole and add one
-additional one:
-\begin{verbatim}
-\setcoffinpole \aaa [h]{t}(\height -3pt)
-\setcoffinpole \aaa [v]{l}(0pt)
-\setcoffinpole \aaa [h]{mybottom}(\depth +2pt)
-\showcoffindata \aaa
-\end{verbatim}
-\setcoffinpole \aaa [h]{t}(\height -3pt)
-\setcoffinpole \aaa [v]{l}(0pt)
-\setcoffinpole \aaa [h]{mybottom}(\depth +2pt)
-\showcoffindata \aaa
-
-
-More interesting in many cases is the relative move of poles. For this the
-poles better exist or one gets an error and \texttt{0pt,0pt} is used:
-\begin{verbatim}
-\adjustcoffinpole \aaa [h]{H}(1pt)
-\adjustcoffinpole \aaa [v]{l}(1pt)
-\adjustcoffinpole \aaa [h]{undefined}(1pt)
-\showcoffindata \aaa
-\end{verbatim}
-\adjustcoffinpole \aaa [h]{H}(1pt)
-\adjustcoffinpole \aaa [v]{l}(1pt)
-\adjustcoffinpole \aaa [h]{undefined}(1pt)
-\showcoffindata \aaa
-
-
-
-\sbox \aaa {\fontsize{14.4}{5.5pc minus .5pc}\sffamily C\,H\,A\,P\,T\,E\,R
- \fontsize{36}{40pt}\selectfont 2}
-
-\setvcoffin \bbb {11cm}
- {\raggedleft\normalfont\fontsize{36}{38pt}\bfseries
- The Structure of a \LaTeX{} Document}
-
-\setvcoffin \ccc {13cm}
- {Some sample blind text to produce paragraph data after a heading.
- Some sample blind text to produce paragraph data after a heading.
- Some sample blind text to produce paragraph data after a heading.
- Some sample blind text to produce paragraph data after a heading.
- \endgraf
- Some more sample blind text to produce paragraph data after a heading.
- Some more sample blind text to produce paragraph data after a heading.
-}
-
-
-Suppose you have the following blocks of text:
-
-\bigskip
-
-\noindent\cbox{\usebox\aaa}
-
-\begin{multicols}{2}
-\ttfamily\tiny
-\ExplSyntaxOn
- \noindent \coffin_print_pole_values:Nn \aaa \\
-\ExplSyntaxOff
-\end{multicols}
-
-\medskip
-
-\noindent\cbox{\usebox\bbb}
-
-\medskip
-
-\noindent\cbox{\usebox\ccc}
-
-\bigskip
-
-produced by:
-\begin{verbatim}
-\sbox \aaa {\fontsize{14.4}{5.5pc minus .5pc}\sffamily
- C\,H\,A\,P\,T\,E\,R
- \fontsize{36}{40pt}\selectfont 2}
-\setvcoffin \bbb {11cm}
- {\raggedleft\normalfont\fontsize{36}{38pt}\bfseries
- The Structure of a \LaTeX{} Document}
-\setvcoffin \ccc {13cm}
- {Some sample blind text to produce paragraph
- data after a heading. ... }
-\end{verbatim}
-
-How do you turn this into a heading of TLC2?
-
-
-\newbox\RBi
-\newbox\RBii
-\newbox\RBiii
-
-\hrulebox\RBi{62pt}
-\vrulebox\RBii{90pt}
-\vrulebox\RBiii{60pt}
-
-\aligncoffins \bbb [T,r] \aaa [H,r](-62pt,60pt)
-\aligncoffins \ccc[T,r] \bbb[B,r](62pt,90pt)
-
- \aligncoffins * \ccc[\bbb-T,\bbb-hc] \RBiii[b,hc](28pt,0pt)
- \aligncoffins * \ccc[\bbb-b,\bbb-r] \RBi[H,r](0pt,-5pt)
- \aligncoffins * \ccc[\bbb-B,\bbb-hc] \RBii[t,r](14pt,0pt)
-
-\newpage
-
-How do you best define/describe the following design?
-
-\medskip
-
-\noindent\cbox{\usebox\ccc}
-
-
-
-
-
-
-\newpage \pagestyle{empty}
-
-\newcoffin \eee
-\newcoffin \fff
-\newcoffin \ggg
-
-\sbox \aaa {\small\scshape les vases communicants}
-\sbox \bbb {\scshape comunicating}
-\sbox \ccc {\fontsize{70pt}{60pt} \bfseries Ve\S els}
-\sbox \ddd {\scshape andr\'e breton}
-\setvcoffin \eee {4.7cm}{\noindent Translated by Mary Ann Caws \&\break
- Geoffrey T.\,Harris, with notes \&\break
- introduction by Mary Ann Caws\parfillskip=0pt\relax
- }
-\sbox \fff {University of Nebraska Press: Lincoln \& London}
-
-\setvcoffin \ggg {100mm}{\noindent\fbox{\parbox{97mm}{\leavevmode\vspace*{228mm}}}}
-
-
-\aligncoffins \ccc [H,r] \ddd [H,r](0pt,-12pt)
-\aligncoffins \ccc [t,l] \bbb (0pt,6pt)
-\aligncoffins \ccc [H,r] \aaa [H,r](0pt,138pt)
-\aligncoffins \eee [T,l] \ccc (0pt,22pc)
-\aligncoffins \fff \eee [B,l](0pt,4pc)
-\aligncoffins \ggg [b,l] \fff [B,l](54pt,11pc)
-
-
-\vspace*{-2cm}
-\noindent\cbox{\usebox\ggg}
-
-
-\newpage
-
-\section{Rotation}
-
-\sbox \aaa {\tabcolsep0pt\begin{tabular}[c]{|c|}\hline a\\b\\cccccccccccccc\\d
- \\e\\e\\e\\e\\\hline\end{tabular}}
-\sbox \bbb {\fbox{A sample Text}}
-
-% just for the sake of it:
-\adjustcoffinpole \aaa {T}(24pt)
-\displaycoffinpoles \aaa {black}
-x\cbox{\usebox \aaa }x
-%
-\rotatecoffin \aaa {45}
-\displaycoffinhandle \aaa {b}{hc} {blue}
-\displaycoffinhandle \aaa {b}{l} {blue}
-\displaycoffinhandle \aaa {t}{r} {blue}
-\displaycoffinhandle \aaa {vc}{r} {blue}
-\displaycoffinhandle \aaa {vc}{l} {blue}
-\quad
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {45}
-\displaycoffinhandle \aaa {b}{r} {red}
-\displaycoffinhandle \aaa {vc}{l} {red}
-\quad
-x\cbox{\usebox \aaa }x
-
-\vspace{1cm}
-
-\rotatecoffin \aaa {45}
-\displaycoffinhandle \aaa {b}{l} {yellow}
-%
-x\cbox{\usebox \aaa }x
-%
-
-\vspace{1cm}
-
-x\cbox{\usebox \bbb }x
-%
-\rotatecoffin \bbb {45}
-\displaycoffinhandle \bbb {B}{hc} {yellow}
-\quad
-x\cbox{\usebox \bbb }x
-
-
-\section{Rotation + alignment}
-
-\aligncoffins \aaa [b,l] \bbb[B,hc](30pt,0pt)
-x\cbox{\usebox \aaa }x
-
-
-After we have aligned a roated box with some other box we need to decide about
-the bounding box of the new box. Right now this become the enclosing box and
-we do not maintain information about the inner boxes. So when we rotate that
-new box there seems to be unnecessary space in the enclosing bounding box,
-even though that is correct if you think of the aligned box being unrotated.
-
-There is at least the possibility to refer to the handles of the inner boxes
-as one can see by two of the green handles
-
-\medskip
-
-\rotatecoffin \aaa {45}
-\displaycoffinhandle \aaa {vc}{hc} {green}
-\displaycoffinhandle \aaa {H}{l} {green}
-\displaycoffinhandle \aaa {\aaa-T}{\aaa-r} {green}
-\displaycoffinhandle \aaa {\bbb-H}{\bbb-r} {green}
-%\quad
-x\cbox{\usebox \aaa }x
-
-We could do better, if we want to, by actually checking for max and
-min of all inner bounding box corners and construct the result BB box from
-that---but is it worth it?
-
-Perhaps it is! After all, the current implementation shows different results
-depending on when you align boxes and when you rotate, e.g., aligning first
-gives totally different bounding box results.
-
-\newpage
-
-Aligning first and then 135 + 45 rotation gives this:
-
-\sbox \aaa {\tabcolsep0pt\begin{tabular}[c]{|c|}\hline a\\b\\cccccccccccccc\\d
- \\e\\e\\e\\e\\\hline\end{tabular}}
-\sbox \bbb {\fbox{A sample Text}}
-\rotatecoffin \bbb {90}
-
-\aligncoffins \aaa [b,l] \bbb[B,hc](-30pt,0pt)
-x\cbox{\usebox \aaa }x
-\qquad
-\rotatecoffin \aaa {135}
-x\cbox{\usebox \aaa }x
-\qquad
-\rotatecoffin \aaa {45}
-x\cbox{\usebox \aaa }x
-
-
-
-
-\newpage
-
-\section{Rotation by small amounts}
-
-\sbox \aaa {\tabcolsep0pt\begin{tabular}[c]{|c|}\hline a\\b\\ccccccccc\\d
- \\e\\e\\e\\\hline\end{tabular}}
-
-\subsection{30 + 30 +30 }
-\rotatecoffin \aaa {30}
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {30}
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {30}
-x\cbox{\usebox \aaa }x
-
-\subsection{6 * 10 + 45 + 45 + 30}
-
-\rotatecoffin \aaa {10}
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {10}
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {10}
-x\cbox{\usebox \aaa }x
-
-\vspace{1cm}
-\rotatecoffin \aaa {10}
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {10}
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {10}
-x\cbox{\usebox \aaa }x
-
-\vspace{1cm}
-\rotatecoffin \aaa {45}
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {45}
-x\cbox{\usebox \aaa }x
-\rotatecoffin \aaa {30}
-x\cbox{\usebox \aaa }x
-
-
-\end{document}
-
-
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-tschichold-example-keyval.tex b/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-tschichold-example-keyval.tex
deleted file mode 100644
index e83c0b490b6..00000000000
--- a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-tschichold-example-keyval.tex
+++ /dev/null
@@ -1,281 +0,0 @@
-
-\documentclass{article}
-
-\usepackage[a4paper,margin=5pt]{geometry}
-
-\usepackage[T1]{fontenc}
-\usepackage{times,multicol,graphicx}
-\usepackage{xcoffins}
-
-\usepackage{times,color}
-\newcommand\cbox[2][.8]{{\setlength\fboxsep{0pt}\colorbox[gray]{#1}{#2}}}
-
-\ExplSyntaxOn
-
-\ExplSyntaxOff
-
-
-
-%\scrollmode
-
-\pagestyle{empty}
-
-\begin{document}
-
- \NewCoffin \result
- \NewCoffin \aaa
- \NewCoffin \bbb
- \NewCoffin \ccc
- \NewCoffin \ddd
- \NewCoffin \eee
- \NewCoffin \fff
- \NewCoffin \rulei
- \NewCoffin \ruleii
- \NewCoffin \ruleiii
-
-\SetHorizontalCoffin \result {}
-\SetHorizontalCoffin \aaa {\fontsize{52}{50}\sffamily\bfseries mitteilungen}
-\SetHorizontalCoffin \bbb {\fontsize{52}{50}\sffamily\bfseries typographische}
-\SetHorizontalCoffin \ccc {\fontsize{12}{10}\sffamily
- \quad zeitschrift des bildungsverbandes der
- deutschen buchdrucker leipzig
- \textbullet{} oktoberheft 1925}
-\SetHorizontalCoffin \ddd {\fontsize{28}{20}\sffamily sonderheft}
-\SetVerticalCoffin \eee {180pt}
- {\raggedleft\fontsize{31}{36}\sffamily\bfseries
- elementare\\
- typographie}
-\SetVerticalCoffin \fff {140pt}
- {\raggedright \fontsize{13}{14}\sffamily\bfseries
- natan altman \\
- otto baumberger \\
- herbert mayer \\
- max burchartz \\
- el lissitzky \\
- ladislaus moholy-nagy \\
- moln\'ar f.~farkas \\
- johannes molzahn \\
- kurt schwitters \\
- mart stam \\
- ivan tschichold}
-
-\RotateCoffin \bbb {90}
-\RotateCoffin \ccc {270}
-
-\SetHorizontalCoffin \rulei {\color{red}\rule{6.5in}{1pc}}
-\SetHorizontalCoffin \ruleii {\color{red}\rule{1pc}{23.5cm}}
-\SetHorizontalCoffin \ruleiii{\color{black}\rule{10pt}{152pt}}
-
-
-\JoinCoffins \result \aaa
-\JoinCoffins [
- coffin1-hpole = \aaa-t ,
- coffin1-vpole = \aaa-r ,
- coffin2-hpole = b ,
- coffin2-vpole = r ,
- voffset = 2 mm ,
-] \result \rulei
-\JoinCoffins [
- coffin1-hpole = \aaa-b ,
- coffin1-vpole = \aaa-l ,
- coffin2-hpole = B ,
- coffin2-vpole = r ,
- hoffset = 2 pt ,
-] \result \bbb
-\JoinCoffins [
- coffin1-hpole = \bbb-t ,
- coffin1-vpole = \bbb-r ,
- coffin2-hpole = t ,
- coffin2-vpole = r ,
- hoffset = -2 mm ,
-] \result \ruleii
-\JoinCoffins [
- coffin1-hpole = \aaa-B ,
- coffin1-vpole = \aaa-r ,
- coffin2-hpole = B ,
- coffin2-vpole = l ,
- hoffset = 66 pt ,
- voffset = 14 pc ,
-] \result \ccc
-\JoinCoffins [
- coffin1-hpole = \bbb-l ,
- coffin1-vpole = \ccc-B ,
- coffin2-hpole = t ,
- coffin2-vpole = r ,
- hoffset = -2 mm ,
-] \result \fff
-\JoinCoffins [
- coffin1-hpole = \fff-b ,
- coffin1-vpole = \fff-r ,
- coffin2-hpole = b ,
- coffin2-vpole = l ,
- hoffset = 2 mm ,
-] \result \ruleiii
-\JoinCoffins [
- coffin1-hpole = \ccc-r ,
- coffin1-vpole = \fff-l ,
- coffin2-hpole = B ,
- coffin2-vpole = r ,
-] \result \eee
-\JoinCoffins [
- coffin1-hpole = \eee-T ,
- coffin1-vpole = \eee-r ,
- coffin2-hpole = B ,
- coffin2-vpole = r ,
- voffset = 4 pc ,
-] \result \ddd
-
-
-\vspace*{3cm}
-\begin{center}
- {\Large Title page of ``elementare typographie'' by Ivan Tschichold\par}
-
-\large
-\vspace*{1cm}
-
- 1. first the scanned original from 1925
-
-\vspace*{6mm}
-
- 2. then the recreated \TeX{} version from 2010 using coffins---not
- attempting\\ to match the fonts and size but the structure
-
-\vspace*{6mm}
-
- 3. and finally the source code used.
-
- This document uses the new
- implementation by Joseph in \texttt{l3coffins-new}.
-
-\end{center}
-
-\newpage
-
-
-\begin{center}
- \null
- \fbox{\includegraphics[scale=.95]{elementare-typographie-title.jpg}}
-\end{center}
-
-\newpage
-
-\TypesetCoffin \result
-
-\newpage
-
-\vspace*{3cm}
-\begin{center}
- {\Large Code used: \par}
-\vspace*{1cm}
-
-
-\begin{minipage}{14cm}
-\begin{verbatim}
-\SetHorizontalCoffin\result{}
-\SetHorizontalCoffin \aaa {\fontsize{52}{50}\sffamily\bfseries mitteilungen}
-\SetHorizontalCoffin \bbb {\fontsize{52}{50}\sffamily\bfseries typographische}
-\SetHorizontalCoffin \ccc {\fontsize{12}{10}\sffamily
- \quad zeitschrift des bildungsverbandes der
- deutschen buchdrucker leipzig
- \textbullet{} oktoberheft 1925}
-\SetHorizontalCoffin \ddd {\fontsize{28}{20}\sffamily sonderheft}
-\SetVerticalCoffin \eee {180pt}
- {\raggedleft\fontsize{31}{36}\sffamily\bfseries
- elementare\\
- typographie}
-\SetVerticalCoffin \fff {140pt}
- {\raggedright \fontsize{13}{14}\sffamily\bfseries
- natan altman \\
- otto baumberger \\
- herbert mayer \\
- max burchartz \\
- el lissitzky \\
- ladislaus moholy-nagy \\
- moln\'ar f.~farkas \\
- jahannes molzahn \\
- kurt schwitters \\
- mart stam \\
- ivan tschichold}
-
-\RotateCoffin \bbb {90}
-\RotateCoffin \ccc {270}
-
-\SetHorizontalCoffin \rulei {\color{red}\rule{6.5in}{1pc}}
-\SetHorizontalCoffin \ruleii {\color{red}\rule{1pc}{23.5cm}}
-\SetHorizontalCoffin \ruleiii{\color{black}\rule{10pt}{152pt}}
-
-\JoinCoffins \result \aaa
-\JoinCoffins [
- coffin1-hpole = \aaa-t ,
- coffin1-vpole = \aaa-r ,
- coffin2-hpole = b ,
- coffin2-vpole = r ,
- voffset = 2 mm ,
-] \result \rulei
-\JoinCoffins [
- coffin1-hpole = \aaa-b ,
- coffin1-vpole = \aaa-l ,
- coffin2-hpole = B ,
- coffin2-vpole = r ,
- hoffset = 2 pt ,
-] \result \bbb
-\JoinCoffins [
- coffin1-hpole = \bbb-t ,
- coffin1-vpole = \bbb-r ,
- coffin2-hpole = t ,
- coffin2-vpole = r ,
- hoffset = -2 mm ,
-] \result \ruleii
-\JoinCoffins [
- coffin1-hpole = \aaa-B ,
- coffin1-vpole = \aaa-r ,
- coffin2-hpole = B ,
- coffin2-vpole = l ,
- hoffset = 66 pt ,
- voffset = 14 pc ,
-] \result \ccc
-\JoinCoffins [
- coffin1-hpole = \bbb-l ,
- coffin1-vpole = \ccc-B ,
- coffin2-hpole = t ,
- coffin2-vpole = r ,
- hoffset = -2 mm ,
-] \result \fff
-\JoinCoffins [
- coffin1-hpole = \fff-b ,
- coffin1-vpole = \fff-r ,
- coffin2-hpole = b ,
- coffin2-vpole = l ,
- hoffset = 2 mm ,
-] \result \ruleiii
-\JoinCoffins [
- coffin1-hpole = \ccc-r ,
- coffin1-vpole = \fff-l ,
- coffin2-hpole = B ,
- coffin2-vpole = r ,
-] \result \eee
-\JoinCoffins [
- coffin1-hpole = \eee-T ,
- coffin1-vpole = \eee-r ,
- coffin2-hpole = B ,
- coffin2-vpole = r ,
- voffset = 4 pc ,
-] \result \ddd
-\SetHorizontalCoffin\result{}
-\SetHorizontalCoffin \aaa {\fontsize{52}{50}\sffamily\bfseries
- mitteilungen}
-\SetHorizontalCoffin \bbb {\fontsize{52}{50}\rotatebox{90}{\sffamily\bfseries
- typographische}}
-
-\TypesetCoffin \result
-\end{verbatim}
-
-This is not necessarily the final syntax but for now it does its job. For
-example, flexible support for adding ornaments (lines, \ldots) is still
-missing, so above the rules got added as predefined individual coffins.
-
-\end{minipage}
-\end{center}
-
-\end{document}
-
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-tschichold-example.tex b/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-tschichold-example.tex
deleted file mode 100644
index 343c9d7e29f..00000000000
--- a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins-tschichold-example.tex
+++ /dev/null
@@ -1,185 +0,0 @@
-
-\documentclass{article}
-
-\usepackage[a4paper,margin=5pt]{geometry}
-
-\usepackage[T1]{fontenc}
-\usepackage{times,multicol,graphicx}
-\usepackage{xcoffins}
-
-\usepackage{times,color}
-\newcommand\cbox[2][.8]{{\setlength\fboxsep{0pt}\colorbox[gray]{#1}{#2}}}
-
-\ExplSyntaxOn
-
-\ExplSyntaxOff
-
-
-
-%\scrollmode
-
-\pagestyle{empty}
-
-\begin{document}
-
- \NewCoffin \result
- \NewCoffin \aaa
- \NewCoffin \bbb
- \NewCoffin \ccc
- \NewCoffin \ddd
- \NewCoffin \eee
- \NewCoffin \fff
- \NewCoffin \rulei
- \NewCoffin \ruleii
- \NewCoffin \ruleiii
-
-\SetHorizontalCoffin \result {}
-\SetHorizontalCoffin \aaa {\fontsize{52}{50}\sffamily\bfseries mitteilungen}
-\SetHorizontalCoffin \bbb {\fontsize{52}{50}\sffamily\bfseries typographische}
-\SetHorizontalCoffin \ccc {\fontsize{12}{10}\sffamily
- \quad zeitschrift des bildungsverbandes der
- deutschen buchdrucker leipzig
- \textbullet{} oktoberheft 1925}
-\SetHorizontalCoffin \ddd {\fontsize{28}{20}\sffamily sonderheft}
-\SetVerticalCoffin \eee {180pt}
- {\raggedleft\fontsize{31}{36}\sffamily\bfseries
- elementare\\
- typographie}
-\SetVerticalCoffin \fff {140pt}
- {\raggedright \fontsize{13}{14}\sffamily\bfseries
- natan altman \\
- otto baumberger \\
- herbert mayer \\
- max burchartz \\
- el lissitzky \\
- ladislaus moholy-nagy \\
- moln\'ar f.~farkas \\
- johannes molzahn \\
- kurt schwitters \\
- mart stam \\
- ivan tschichold}
-
-\RotateCoffin \bbb {90}
-\RotateCoffin \ccc {270}
-
-\SetHorizontalCoffin \rulei {\color{red}\rule{6.5in}{1pc}}
-\SetHorizontalCoffin \ruleii {\color{red}\rule{1pc}{23.5cm}}
-\SetHorizontalCoffin \ruleiii{\color{black}\rule{10pt}{152pt}}
-
-
-\JoinCoffins \result \aaa
-\JoinCoffins \result[\aaa-t,\aaa-r] \rulei [b,r](0pt,2mm)
-\JoinCoffins \result[\aaa-b,\aaa-l] \bbb [B,r](2pt,0pt)
-\JoinCoffins \result[\bbb-t,\bbb-r] \ruleii [t,r](-2mm,0pt)
-\JoinCoffins \result[\aaa-B,\aaa-r] \ccc [B,l](66pt,14pc)
-\JoinCoffins \result[\bbb-l,\ccc-B] \fff [t,r](-2mm,0pt)
-\JoinCoffins \result[\fff-b,\fff-r] \ruleiii [b,l](2mm,0pt)
-\JoinCoffins \result[\ccc-r,\fff-l] \eee [B,r]
-\JoinCoffins \result[\eee-T,\eee-r] \ddd [B,r](0pt,4pc)
-
-
-\vspace*{3cm}
-\begin{center}
- {\Large Title page of ``elementare typographie'' by Ivan Tschichold\par}
-
-\large
-\vspace*{1cm}
-
- 1. first the scanned original from 1925
-
-\vspace*{6mm}
-
- 2. then the recreated \TeX{} version from 2010 using coffins---not
- attempting\\ to match the fonts and size but the structure
-
-\vspace*{6mm}
-
- 3. and finally the source code used.
-
- This document uses the new
- implementation by Joseph in \texttt{l3coffins-new}.
-
-\end{center}
-
-\newpage
-
-
-\begin{center}
- \null
- \fbox{\includegraphics[scale=.95]{elementare-typographie-title.jpg}}
-\end{center}
-
-\newpage
-
-\TypesetCoffin \result
-
-\newpage
-
-\vspace*{3cm}
-\begin{center}
- {\Large Code used: \par}
-\vspace*{1cm}
-
-
-\begin{minipage}{14cm}
-\begin{verbatim}
-\SetHorizontalCoffin\result{}
-\SetHorizontalCoffin \aaa {\fontsize{52}{50}\sffamily\bfseries mitteilungen}
-\SetHorizontalCoffin \bbb {\fontsize{52}{50}\sffamily\bfseries typographische}
-\SetHorizontalCoffin \ccc {\fontsize{12}{10}\sffamily
- \quad zeitschrift des bildungsverbandes der
- deutschen buchdrucker leipzig
- \textbullet{} oktoberheft 1925}
-\SetHorizontalCoffin \ddd {\fontsize{28}{20}\sffamily sonderheft}
-\SetVerticalCoffin \eee {180pt}
- {\raggedleft\fontsize{31}{36}\sffamily\bfseries
- elementare\\
- typographie}
-\SetVerticalCoffin \fff {140pt}
- {\raggedright \fontsize{13}{14}\sffamily\bfseries
- natan altman \\
- otto baumberger \\
- herbert mayer \\
- max burchartz \\
- el lissitzky \\
- ladislaus moholy-nagy \\
- moln\'ar f.~farkas \\
- jahannes molzahn \\
- kurt schwitters \\
- mart stam \\
- ivan tschichold}
-
-\RotateCoffin \bbb {90}
-\RotateCoffin \ccc {270}
-
-\SetHorizontalCoffin \rulei {\color{red}\rule{6.5in}{1pc}}
-\SetHorizontalCoffin \ruleii {\color{red}\rule{1pc}{23.5cm}}
-\SetHorizontalCoffin \ruleiii{\color{black}\rule{10pt}{152pt}}
-
-\JoinCoffins \result \aaa
-\JoinCoffins \result[\aaa-t,\aaa-r] \rulei [b,r](0pt,2mm)
-\JoinCoffins \result[\aaa-b,\aaa-l] \bbb [B,r](2pt,0pt)
-\JoinCoffins \result[\bbb-t,\bbb-r] \ruleii [t,r](-2mm,0pt)
-\JoinCoffins \result[\aaa-B,\aaa-r] \ccc [B,l](66pt,14pc)
-\JoinCoffins \result[\bbb-l,\ccc-B] \fff [t,r](-2mm,0pt)
-\JoinCoffins \result[\fff-b,\fff-r] \ruleiii [b,l](2mm,0pt)
-\JoinCoffins \result[\ccc-r,\fff-l] \eee [B,r]
-\JoinCoffins \result[\eee-T,\eee-r] \ddd [B,r](0pt,4pc)
-\SetHorizontalCoffin\result{}
-\SetHorizontalCoffin \aaa {\fontsize{52}{50}\sffamily\bfseries
- mitteilungen}
-\SetHorizontalCoffin \bbb {\fontsize{52}{50}\rotatebox{90}{\sffamily\bfseries
- typographische}}
-
-\TypesetCoffin \result
-\end{verbatim}
-
-This is not necessarily the final syntax but for now it does its job. For
-example, flexible support for adding ornaments (lines, \ldots) is still
-missing, so above the rules got added as predefined individual coffins.
-
-\end{minipage}
-\end{center}
-
-\end{document}
-
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf b/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf
index b9f4e0ae361..b20f638d514 100644
--- a/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf
+++ b/Master/texmf-dist/doc/latex/l3experimental/xcoffins/xcoffins.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf b/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf
new file mode 100644
index 00000000000..3cad13a681f
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/l3experimental/xgalley/l3galley.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf b/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf
new file mode 100644
index 00000000000..38d903ad9fb
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/l3experimental/xgalley/xgalley.pdf
Binary files differ
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx
new file mode 100644
index 00000000000..e2977e2b249
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx
@@ -0,0 +1,3545 @@
+% \iffalse meta-comment
+%
+%% File: l3regex.dtx Copyright (C) 2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX3 Project.
+%%
+%% -----------------------------------------------------------------------
+%
+%<*driver|package>
+\RequirePackage{expl3}
+\GetIdInfo$Id: l3regex.dtx 2895 2011-10-09 15:58:19Z joseph $
+ {L3 Experimental Regular Expressions}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\usepackage{amsmath}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \textsf{l3regex} package: regular expressions in \TeX{}^^A
+% \thanks{This file describes v\ExplFileVersion,
+% last revised \ExplFileDate.}^^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 \ExplFileDate}
+%
+% \maketitle
+%
+% \begin{documentation}
+% \newenvironment{l3regex-syntax}
+% {\begin{itemize}\def\makelabel##1{\hss\llap{\ttfamily\string##1}}}
+% {\end{itemize}}
+%
+% \section{\pkg{l3regex} documentation}
+%
+% The \pkg{l3regex} package provides regular expression testing,
+% extraction of submatches, splitting, and replacement, all acting on strings
+% of characters. The syntax of regular expressions is mostly a subset
+% of the PCRE syntax (and very close to POSIX). For performance
+% reasons, only a limited set of features are implemented. Notably,
+% back-references are not supported.
+%
+% Let us give a few examples. After
+% \begin{verbatim}
+% \str_set:Nn \l_my_str { That~cat. }
+% \regex_replace_once:nnN { at } { is } \l_my_str
+% \end{verbatim}
+% the string variable \cs{l_my_str} holds the text
+% \enquote{\texttt{This cat.}}, where the first
+% occurrence of \enquote{\texttt{at}} was replaced
+% by \enquote{\texttt{is}}. A more complicated example is
+% a pattern to add a comma at the end of each word:
+% \begin{verbatim}
+% \regex_replace_all:nnN { (\w+) } { \1 , } \l_my_str
+% \end{verbatim}
+% The |\w| sequence represents any \enquote{word} character,
+% and |*| indicates that the |\w| sequence should be repeated
+% as many times as possible, hence matching a word in the
+% input string. The parentheses \enquote{capture} what their
+% contents matched in the input string, and this can be used
+% in the replacement text as |\1| (and higher numbers if several
+% groups are used in the regular expression).
+%
+% \subsection{Syntax of regular expressions}
+%
+% Most characters match exactly themselves. Some characters are
+% special and must be escaped with a backslash (\emph{e.g.}, |\*|
+% matches an explicit star character). Some escape sequences of
+% the form backslash--letter also have a special meaning
+% (for instance |\d| matches any digit). As a rule,
+% \begin{itemize}
+% \item every alphanumeric character (\texttt{A}--\texttt{Z},
+% \texttt{a}--\texttt{z}, \texttt{0}--\texttt{9}) matches
+% exactly itself, none of them should be escaped, because
+% most of those escape sequences have special meanings;
+% \item non-alphanumeric printable ascii characters can always
+% be safely escaped, and for highest portability, they should
+% always be escaped (this avoids problems if some currently
+% \enquote{normal} characters is given a meaning in later
+% releases);
+% \item spaces should always be escaped (even in character
+% classes);
+% \item any other character may be escaped or not, without any
+% effect: both versions will match exactly that character.
+% \end{itemize}
+% Note that these rules play nicely with the fact that many
+% non-alphanumeric characters are difficult to input into \TeX{}
+% under normal category codes. For instance, |\$\%\^\\abc\#|
+% matches the literal string |$%^\abc#|.
+% \begin{texnote}
+% When converting the regular expression to a string,
+% the value of the escape character is set to be a backslash.
+% \end{texnote}
+%
+% Any special character which appears at a place where its special
+% behaviour cannot apply matches itself instead (for instance,
+% a quantifier appearing at the beginning of a string).
+%
+% Characters.
+% \begin{l3regex-syntax}
+% \item[\x\{hh\ldots{}\}]
+% Character with hex code \texttt{hh\ldots{}}
+% \item[\xhh]
+% Character with hex code \texttt{hh}.
+% \item[\a] Alarm (hex 07).
+% \item[\e] Escape (hex 1B).
+% \item[\f] Form-feed (hex 0C).
+% \item[\n] New line (hex 0A).
+% \item[\r] Carriage return (hex 0D).
+% \item[\t] Horizontal tab (hex 09).
+% \end{l3regex-syntax}
+%
+% Character types.
+% \begin{l3regex-syntax}
+% \item[.] A single period matches any character,
+% including newlines.\footnote{Should that be changed?}
+% \item[\N] A character that is not
+% the |\n| character (hex 0A).\footnote{Is that right?}
+% \item[\d] Any decimal digit.
+% \item[\h] Any horizontal space character,
+% equivalent to |[\^^I\ ]|: space and tab.
+% \item[\s] Any space character,
+% equivalent to |[\^^I\^^J\^^L\^^M\ ]|.
+% \item[\v] Any vertical space character,
+% equivalent to |[\^^I-\^^M]|. Note that |\^^K| is a vertical space,
+% but not a space, for compatibility with perl.
+% \item[\w] Any word character, \emph{i.e.},
+% alpha-numerics and underscore, equivalent to |[A-Za-z0-9\_]|.
+% \item[\D] Any character not matched by |\d|.
+% \item[\H] Any character not matched by |\h|.
+% \item[\S] Any character not matched by |\s|.
+% \item[\V] Any character not matched by |\v|.
+% \item[\W] Any character not matched by |\w|.
+% \end{l3regex-syntax}
+%
+% Character classes match exactly one character in the subject string.
+% \begin{l3regex-syntax}
+% \item[{[...]}] Positive character class.
+% \item[{[\string^...]}] Negative character class.
+% \item[{[x-y]}] Range (can be used with escaped characters).
+% \end{l3regex-syntax}
+%
+% Quantifiers.
+% \begin{l3regex-syntax}
+% \item[?] $0$ or $1$, greedy.
+% \item[??] $0$ or $1$, lazy.
+% \item[*] $0$ or more, greedy.
+% \item[*?] $0$ or more, lazy.
+% \item[+] $1$ or more, greedy.
+% \item[+?] $1$ or more, lazy.
+% \end{l3regex-syntax}
+% Not implemented yet: ^^A !
+% \begin{l3regex-syntax}\def\makelabel#1{\hss\llap{\ttfamily#1}}
+% \item[\{$n$\}] Exactly $n$.
+% \item[\{$n,$\}] $n$ or more, greedy.
+% \item[\{$n,$\}?] $n$ or more, lazy.
+% \item[\{$n,m$\}] At least $n$, no more than $m$, greedy.
+% \item[\{$n,m$\}?] At least $n$, no more than $m$, lazy.
+% \end{l3regex-syntax}
+%
+% Anchors and simple assertions.
+% \begin{l3regex-syntax}
+% \item[\b] Word boundary.
+% \item[\B] Not a word boundary.
+% \item[^\string\A] Start of the subject string.\footnote{The
+% multiline mode is not implemented yet, so those are currently
+% identical.}
+% \item[$\string\Z\string\z] End of the subject
+% string.\footnotemark[\thefootnote]
+% \item[\G] Start of the current match. This is only different from |^|
+% in the case of multiple matches: for instance
+% |\regex_count:nnN { \G a } { aaba } \l_tmpa_int| yields $2$, but
+% replacing |\G| by |^| would result in \cs{l_tmpa_int} holding the
+% value $1$.
+% \end{l3regex-syntax}
+%
+% Alternation and capturing groups.
+% \begin{l3regex-syntax}
+% \item[A\string|B\string|C] Either one of \texttt{A}, \texttt{B},
+% or \texttt{C}.
+% \item[(\ldots{})] Capturing group.
+% \item[(?:\ldots{})] Non-capturing group.
+% \end{l3regex-syntax}
+%
+% In character classes, only |^|, |-|, |]|, |\| and spaces are special,
+% and should be escaped. Other non-alphanumeric characters can
+% still be escaped without harm. The escape sequences |\d|,
+% |\D|, |\w|, |\W| are also supported in character classes.
+% If the first character is |^|, then the meaning of the character
+% class is inverted. Ranges of characters can be expressed using
+% |-|, for instance, |[\D 0-5]| is equivalent to |[^6-9]|.
+%
+% Capturing groups are a means of extracting information about the
+% match. Parenthesized groups are labelled in the order of their
+% opening parenthesis, starting at $1$. The contents of those groups
+% corresponding to the \enquote{best} match (leftmost longest)
+% can be extracted and stored in a sequence of strings using for
+% instance \cs{regex_extract:nnNTF}.
+%
+% \subsection{Syntax of in the replacement text}
+%
+% Most of the features described in regular expressions do not make sense
+% within the replacement text. Escaped characters are supported as inside
+% regular expressions. The various submatches are accessed with |\1|, |\2|,
+% \emph{etc.}, and the whole match is accessed using |\0|.
+%
+% For instance,
+% \begin{verbatim}
+% \str_set:Nn \l_my_str { Hello,~world! }
+% \regex_replace_all:nnN { ([er]?l|o) . } { \(\0\-\-\1\) } \l_my_str
+% \end{verbatim}
+% results in \cs{l_my_str} holding |H(ell--el)(o,--o) w(or--o)(ld--l)!|
+%
+% Submatches with numbers higher than $10$ are accessed in the same way,
+% namely |\10|, |\11|, \emph{etc}. To insert in the replacement text
+% a submatch followed by a digit, the digit must be entered using the
+% |\x| escape sequence: for instance, to get the first submatch followed
+% by the digit $7$, use |\1\x37|, because $7$ has character code |37|
+% (in hexadecimal).
+%
+% \subsection{Precompiling regular expressions}
+%
+% If a regular expression is to be used several times,
+% it is better to compile it once rather than doing it
+% each time the regular expression is used. The precompiled
+% regular expression is stored as a token list variable. All
+% of the \pkg{l3regex} module's functions can be given their
+% regular expression argument either as an explicit string
+% or as a precompiled regular expression.
+%
+% \begin{function}{\regex_set:Nn}
+% \begin{function}{\regex_gset:Nn}
+% \begin{syntax}
+% \cs{regex_set:Nn} \meta{tl var} \Arg{regex}
+% \end{syntax}
+% Stores a precompiled version of the \meta{regular expression}
+% in the \meta{tl var}. For instance, this function can be used
+% as
+% \begin{verbatim}
+% \tl_new:N \l_my_regex_tl
+% \regex_set:Nn \l_my_regex_tl { my\ (simple\ )? reg(ex|ular\ expression) }
+% \end{verbatim}
+% The assignment is local for \cs{regex_set:Nn}
+% and global for \cs{regex_gset:Nn}.
+% \begin{texnote}
+% Precompiled regular expressions can be safely written to a file
+% and read when the \LaTeX3 syntax is active (as triggered by
+% \cs{ExplSyntaxOn}).
+% \end{texnote}
+% \end{function}
+% \end{function}
+%
+% \subsection{String matching}
+%
+% \begin{function}[TF]{\regex_match:nn}
+% \begin{function}[TF]{\regex_match:Nn}
+% \begin{syntax}
+% \cs{regex_match:nnTF} \Arg{regex} \Arg{string} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests whether the \meta{regular expression} matches any substring
+% of \meta{string}. For instance,
+% \begin{verbatim}
+% \regex_match:nnTF { b [cde]* } { abecdcx } { TRUE } { FALSE }
+% \regex_match:nnTF { [b-dq-w] } { example } { TRUE } { FALSE }
+% \end{verbatim}
+% leaves \texttt{TRUE FALSE} in the input stream.
+% \end{function}
+% \end{function}
+%
+% \begin{function}{\regex_count:nnN}
+% \begin{function}{\regex_count:NnN}
+% \begin{syntax}
+% \cs{regex_count:nnN} \Arg{regex} \Arg{string} \meta{int var}
+% \end{syntax}
+% Sets \meta{int var} equal to the number of times
+% \meta{regular expression} appears in \meta{string}.
+% The search starts by finding the left-most longest match,
+% respecting greedy and ungreedy operators. Then the search
+% starts again from the character following the last character
+% of the previous match, until reaching the end of the string.
+% For instance,
+% \begin{verbatim}
+% \int_new:N \l_foo_int
+% \regex_count:nnN { (b+|c) } { abbababcbb } \l_foo_int
+% \end{verbatim}
+% results in \cs{l_foo_int} taking the value $5$.
+% \end{function}
+% \end{function}
+%
+% \subsection{Submatch extraction}
+%
+% \begin{function}{\regex_extract:nnN}
+% \begin{function}{\regex_extract:NnN}
+% \begin{function}[TF]{\regex_extract:nnN}
+% \begin{function}[TF]{\regex_extract:NnN}
+% \begin{syntax}
+% \cs{regex_extract:nnNTF} \Arg{regex} \Arg{string} \meta{seq~var} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Finds the first match of the \meta{regular expression}
+% in the \meta{string}. If it exists, the match is stored
+% as the zeroeth item of the \meta{seq~var}, and further
+% items are the contents of capturing groups, in the order
+% of their opening left parenthesis. The \meta{seq~var}
+% is assigned locally. If there is no match,
+% the \meta{seq~var} is not altered.
+% The testing versions return \meta{true} if a match was found,
+% and \meta{false} otherwise.
+% For instance, assume that you type
+% \begin{verbatim}
+% \regex_extract:nnNTF { ^(La)?TeX(!*)$ } { LaTeX!!! }
+% \l_foo_seq { true } { false }
+% \end{verbatim}
+% Then the regular expression (anchored at the start with |^| and
+% at the end with |$|) will match the whole string. The first
+% capturing group, |(La)?|, matches |La|, and the second capturing
+% group, |(!*)|, matches |!!!|. Thus, |\l_foo_seq| will contain
+% the items |{LaTeX!!!}|, |{La}|, and |{!!!}|, and the \texttt{true}
+% branch is left in the input stream.
+% \end{function}
+% \end{function}
+% \end{function}
+% \end{function}
+%
+% \subsection{String splitting}
+%
+% \begin{function}{\regex_split:nnN}
+% \begin{function}{\regex_split:NnN}
+% \begin{syntax}
+% \cs{regex_split:nnN} \Arg{regular expression} \meta{string} \meta{seq~var}
+% \end{syntax}
+% Searches the \meta{string} into a sequence of substrings, delimited by
+% matches of the \meta{regular expression}. If the \meta{regular expression}
+% has capturing groups, then the substrings that they match are stored as
+% items of the sequence as well. The assignment to \meta{seq~var} is local.
+% If no match is found the resulting \meta{seq~var} has the \meta{string} as
+% its sole item. If the \meta{regular expression} matches the empty string,
+% then the \meta{string} is split into single character substrings.
+% \end{function}
+% \end{function}
+%
+% \subsection{String replacement}
+%
+% \begin{function}{\regex_replace_once:nnN}
+% \begin{function}{\regex_replace_once:NnN}
+% \begin{function}[TF]{\regex_replace_once:nnN}
+% \begin{function}[TF]{\regex_replace_once:NnN}
+% \begin{syntax}
+% \cs{regex_replace_once:nnN} \Arg{regular expression} \Arg{replacement} \meta{str~var}
+% \end{syntax}
+% Searches for the \meta{regular expression} in the \meta{string}
+% and replaces the matching part with the \meta{replacement}. The result
+% is assigned locally to \meta{str~var}. In the \meta{replacement},
+% |\0| represents the full match, |\1| represent the contents
+% of the first capturing group, |\2| of the second, \emph{etc.}
+% \end{function}
+% \end{function}
+% \end{function}
+% \end{function}
+%
+% \begin{function}{\regex_replace_all:nnN}
+% \begin{function}{\regex_replace_all:NnN}
+% \begin{syntax}
+% \cs{regex_replace_all:nnN} \Arg{regular expression} \Arg{replacement} \meta{str~var}
+% \end{syntax}
+% Replaces all occurrences of the \cs{regular expression}
+% in the \meta{string} by the \meta{replacement}, where
+% |\0| represents the full match, |\1|
+% represent the contents of the first capturing group,
+% |\2| of the second, \emph{etc.} Every match
+% is treated independently. The result is assigned
+% locally to \meta{str~var}.
+% \end{function}
+% \end{function}
+%
+% \subsection{Bugs, misfeatures, future work, and other possibilities}
+%
+% The \texttt{\{\}} quantifiers are not implemented.
+%
+% The following need discussion.
+% \begin{itemize}
+% \item Newline conventions are not done.
+% In particular, |.| should not match newlines.
+% Also, |\A| should differ from |^|, and |\Z|, |\z| and |$| should
+% differ.
+% \item Caseless matching and more generally
+% |(*..)| and |(?..)| sequences to set some options.
+% \item General look-ahead/behind assertions.
+% \item Idea of |#| as a synonym of |.*?|.
+% \item Do we need a facility for balanced groups? (That's non-regular.)
+% \end{itemize}
+%
+% The following features are likely to be implemented at some point
+% in the future.
+% \begin{itemize}
+% \item Optimize simple strings: use less states
+% (|abcade| should give two states, for |abc| and |ade|).
+% \item Optimize groups with no alternative.
+% \item Optimize the use of \cs{prg_stepwise_...} functions.
+% \item Implement regex matching on external files.
+% \item Conditional subpatterns with look ahead/behind: \enquote{if
+% what follows is [\ldots{}], then [\ldots{}]}.
+% \item "(?|..|..)" to reset the capturing group number at the start
+% of each alternative.
+% \item Todo: check space's catcode in the result of a replacement.
+% \end{itemize}
+%
+% The following features not present in PCRE nor perl (because they can
+% be done in other ways in those languages) might be added.
+% \begin{itemize}
+% \item |#| as a synonym of |.*?|, in a way similar to macro parameters.
+% \item Facility to match balanced groups: this is non-regular, but quite
+% useful, and it can be implemented without too much performance loss.
+% (\emph{cf.} callout?)
+% \end{itemize}
+%
+% The following features of PCRE or perl will probably not be implemented.
+% \begin{itemize}
+% \item Other forms of escapes, and character classes.
+% |\cx|$\simeq$|\^^x|, |\ddd| (octal \texttt{ddd}).
+% POSIX character classes.
+% |\p{..}| and |\P{..}| for having/not having a Unicode property.
+% |\X| for \enquote{extended} Unicode sequence.
+% \item Callout with |(?C...)|.
+% \item Conditional subpatterns (other than with a look-ahead
+% or look-behind condition): this is non-regular, isn't it?
+% \end{itemize}
+%
+% The following features of PCRE or perl will not be implemented.
+% \begin{itemize}
+% \item Comments: \TeX{} already has its own system for comments.
+% \item Named subpatterns: \TeX{} programmers have lived so far without
+% any need for named macro parameters.
+% \item |\Q...\E| escaping: this would require to read the argument
+% verbatim, which is not in the scope of this module.
+% \item Atomic grouping, possessive quantifiers: those tools, mostly
+% meant to fix catastrophic backtracking, are unnecessary in a
+% non-backtracking algorithm, and difficult to implement.
+% \item Subroutine calls: this syntactic sugar is difficult to
+% include in a non-backtracking algorithm, in particular because
+% the corresponding group should be treated as atomic.
+% \item Recursion: this is a non-regular feature.
+% \item Back-references: non-regular feature, this requires backtracking,
+% which is prohibitively slow.
+% \item Backtracking control verbs: intrinsically tied to backtracking.
+% \item |\K| for resetting the beginning of the match: tied to backtracking.
+% \item |\C| single byte in UTF-8 mode: well, UTF-8 mode is not
+% implemented, and that seems like a very rarely useful feature anyways.
+% \end{itemize}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3regex} implementation}
+%
+%<*package>
+% \begin{macrocode}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\RequirePackage{l3str}
+% \end{macrocode}
+%
+% Most regex engines use backtracking. This allows to provide very
+% powerful features (back-references come to mind first), but it is
+% costly. Since \TeX{} is not first and foremost a programming language,
+% complicated code tends to run slowly, and we must use faster, albeit
+% slightly more restrictive, techniques, coming from automata theory.
+%
+% Given a regular expression of $n$ characters, we build a
+% non-deterministic finite automaton (NFA) with roughly $n$ states,
+% which accepts precisely those strings matching that regular expression.
+% We then run the string through the NFA, and check the return value.
+%
+% The code is structured as follows. Various helper functions are
+% introduced in the next subsection, to limit the clutter in later
+% parts. Then functions pertaining to parsing the regular expression
+% are introduced: that part is rather long because of the many bells
+% and whistles that we need to cater for. The next subsection takes
+% care of running the NFA, and describes how the various \TeX{}
+% registers are (ab)used in this module. Finally, user functions.
+%
+% \subsection{Constants and variables}
+%
+% \begin{macro}{\regex_tmp:w}
+% \begin{variable}{\g_regex_tmpa_tl,\l_regex_tmpa_tl,\l_regex_tmpb_tl}
+% \begin{variable}{\l_regex_tmpa_int}
+% Temporary variables.
+% \begin{macrocode}
+\cs_new:Npn \regex_tmp:w { }
+\tl_new:N \g_regex_tmpa_tl
+\tl_new:N \l_regex_tmpa_tl
+\tl_new:N \l_regex_tmpb_tl
+\int_new:N \l_regex_tmpa_int
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+% \end{macro}
+%
+% \subsubsection{Variables used while building}
+%
+% \begin{variable}{\l_regex_pattern_str}
+% The \meta{pattern} is stored in a string variable.
+% \begin{macrocode}
+\tl_new:N \l_regex_pattern_str
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_max_state_int}
+% \begin{variable}{\l_regex_left_state_int,\l_regex_right_state_int}
+% \begin{variable}{\l_regex_left_state_seq,\l_regex_right_state_seq}
+% The last state that was allocated is stored in \cs{l_regex_max_state_int},
+% and \cs{l_regex_left/right_state_int} point to both end-points of the
+% last group (which any quantifier would repeat). For simple strings of
+% characters, the left and right pointers only differ by one.
+% \begin{macrocode}
+\int_new:N \l_regex_max_state_int
+\int_new:N \l_regex_left_state_int
+\int_new:N \l_regex_right_state_int
+\seq_new:N \l_regex_left_state_seq
+\seq_new:N \l_regex_right_state_seq
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_capturing_group_int}
+% \begin{variable}{\l_regex_capturing_group_seq}
+% \cs{l_regex_capturing_group_int} is the id number of the current
+% capturing group, starting at $0$ for a group enclosing the full
+% regular expression, and counting in the order of their left parenthesis.
+% This number is used when a branch of the alternation ends.
+% Capturing groups can be arbitrarily nested, and we keep track of
+% the stack of id numbers in \cs{l_regex_capturing_group_seq}.
+% \begin{macrocode}
+\int_new:N \l_regex_capturing_group_int
+\seq_new:N \l_regex_capturing_group_seq
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_one_or_group_tl}
+% When looking for quantifiers, this variable holds either
+% \enquote{one} or \enquote{group} depending on whether the
+% object to which the quantifier applies matches one character
+% (\emph{i.e.}, is a character or character class), or is a group.
+% \begin{macrocode}
+\tl_new:N \l_regex_one_or_group_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{l_regex_repetition_int}
+% Used when to distinguish threads at the same state but with
+% different repetitions of some quantifiers.
+% \begin{macrocode}
+\int_new:N \l_regex_repetition_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_look_behind_bool}
+% \begin{variable}{\l_regex_look_behind_str}
+% The boolean \cs{l_regex_look_behind_bool} indicates whether
+% a look-behind assertion appears within the regular expression
+% (currently only |\b| or |\B|). When matching, we will keep
+% track of the part of the string before the current character
+% in \cs{l_regex_look_behind_str}, stored backwards.
+% \begin{macrocode}
+\bool_new:N \l_regex_look_behind_bool
+\tl_new:N \l_regex_look_behind_str
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+%
+% \subsubsection{Character classes}
+%
+% \begin{macro}{\regex_build_tmp_class:n}
+% \begin{variable}{\l_regex_class_bool,\l_regex_class_tl}
+% Used when building character classes.
+% \begin{macrocode}
+\cs_new_eq:NN \regex_build_tmp_class:n \use_none:n
+\bool_new:N \l_regex_class_bool
+\tl_new:N \l_regex_class_tl
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{variable}{\c_regex_d_tl,\c_regex_D_tl}
+% \begin{variable}{\c_regex_h_tl,\c_regex_H_tl}
+% \begin{variable}{\c_regex_s_tl,\c_regex_S_tl}
+% \begin{variable}{\c_regex_v_tl,\c_regex_V_tl}
+% \begin{variable}{\c_regex_w_tl,\c_regex_W_tl}
+% \begin{variable}{\c_regex_N_tl}
+% These constant token lists encode which characters
+% are recognized by |\d|, |\D|, |\w|, \emph{etc.}
+% in regular expressions. Namely, |\d=[0-9]|,
+% |\w=[0-9A-Z_a-z]|, |\s=[\ \^^I\^^J\^^L\^^M]|,
+% |\h=[\ \^^I]|, |\v=[\^^J-\^^M]|, and the upper-case
+% counterparts match anything that the lowercase
+% does not match.
+% The order in which the various ranges appear is
+% optimized for usual mostly lowercase letter text.
+% \begin{macrocode}
+\tl_const:Nn \c_regex_d_tl
+ {
+ \regex_item_range:nn {48} {57} % 0--9
+ }
+\tl_const:Nn \c_regex_D_tl
+ {
+ \regex_item_more:n {57} % 9
+ \regex_item_range:nn {0} {47} % 0
+ }
+\tl_const:Nn \c_regex_h_tl
+ {
+ \regex_item_equal:n {32} % space
+ \regex_item_equal:n {9} % tab
+ }
+\tl_const:Nn \c_regex_H_tl
+ {
+ \regex_item_neq:n {32} % space
+ \regex_item_neq:n {9} % tab
+ \regex_break_true:w
+ }
+\tl_const:Nn \c_regex_s_tl
+ {
+ \regex_item_equal:n {32} % space
+ \regex_item_neq:n {11} % vtab
+ \regex_item_range:nn {9} {13} % tab, lf, vtab, ff, cr
+ }
+\tl_const:Nn \c_regex_S_tl
+ {
+ \regex_item_more:n {32} % > space
+ \regex_item_range:nn {14} {31} % tab < ... < space
+ \regex_item_range:nn {0} {8} % < tab
+ \regex_item_equal:n {11} % vtab
+ }
+\tl_const:Nn \c_regex_v_tl
+ {
+ \regex_item_range:nn {10} {13} % lf, vtab, ff, cr
+ }
+\tl_const:Nn \c_regex_V_tl
+ {
+ \regex_item_more:n {13} % cr
+ \regex_item_range:nn {0} {9} % < lf
+ }
+\tl_const:Nn \c_regex_w_tl
+ {
+ \regex_item_range:nn {97} {122} % a--z
+ \regex_item_range:nn {65} {90} % A--Z
+ \regex_item_range:nn {48} {57} % 0--9
+ \regex_item_equal:n {95} % _
+ }
+\tl_const:Nn \c_regex_W_tl
+ {
+ \regex_item_range:nn {0} {47} % <`0
+ \regex_item_range:nn {58} {64} % (`9+1)--(`A-1)
+ \regex_item_range:nn {91} {94} % (`Z+1)--(`_-1)
+ \regex_item_equal:n {96} % `
+ \regex_item_more:n {122} % z
+ }
+\tl_const:Nn \c_regex_N_tl
+ {
+ \regex_item_neq:n {10} % lf
+ \regex_break_true:w
+ }
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+% \end{variable}
+% \end{variable}
+% \end{variable}
+% \end{variable}
+%
+% \subsubsection{Variables used when matching}
+%
+% \begin{variable}{\l_regex_query_str}
+% The string that is being matched.
+% \begin{macrocode}
+\tl_new:N \l_regex_query_str
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_start_step_int}
+% In the case of multiple matches, \cs{l_regex_start_step_int}
+% is equal to the position where the current match
+% attempt began.
+% \begin{macrocode}
+\int_new:N \l_regex_start_step_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_current_char_int}
+% \begin{variable}{\l_regex_current_step_int}
+% The character at the current position in the string,
+% and the current position.
+% \begin{macrocode}
+\int_new:N \l_regex_current_char_int
+\int_new:N \l_regex_current_step_int
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_unique_step_int}
+% This gives a unique identifier to every step in the loop over
+% characters in the string. In the case of a single match, it is
+% equal to \cs{l_regex_current_step_int}, but for multiple matches,
+% it is not reset to the start of the next match, but incremented.
+% A unique identifier is handy when considering whether a state of
+% the automaton has been visited at that step or not, and when
+% tracking submatch information.
+% \begin{macrocode}
+\int_new:N \l_regex_unique_step_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_current_state_int}
+% For every character in the string, each of the active states is
+% considered in turn.
+% The variable \cs{l_regex_current_state_int} holds the state
+% of the NFA which is currently considered.
+% \begin{macrocode}
+\int_new:N \l_regex_current_state_int
+\prop_new:N \l_regex_current_submatches_prop
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_max_index_int}
+% All the currently active states are kept in order of precedence
+% in the \tn{skip} registers, which for our purpose serve as an array:
+% the $i$-th item of the array is \tn{skip}$i$. The largest index used
+% after treating the previous character is \cs{l_regex_max_index_int}.
+% At the start of every step, the whole array is unpacked, so that the
+% space can immediately be reused, and \cs{l_regex_max_index_int} reset
+% to zero, effectively clearing the array.
+% \begin{macrocode}
+\int_new:N \l_regex_max_index_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\l_regex_every_match_tl}
+% Every time a match is found, this token list is used.
+% For single matching, the token list is set to removing
+% the remainder of the query string. For multiple matching,
+% the token list is set to repeat the matching.
+% \begin{macrocode}
+\tl_new:N \l_regex_every_match_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\regex_last_match_empty:F}
+% This function is most often \cs{use:n}, unless the current
+% regular expression can match an empty string at the current
+% position, and has already done so at the previous match attempt.
+% The goal is to break infinite loops.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_last_match_empty_no:F #1 {#1}
+\cs_new_protected:Npn \regex_last_match_empty_yes:F
+ { \int_compare:nNnF \l_regex_start_step_int = \l_regex_current_step_int }
+\cs_new_eq:NN \regex_last_match_empty:F \regex_last_match_empty_no:F
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_regex_success_bool}
+% \begin{variable}{\l_regex_success_step_int}
+% \begin{variable}{\l_regex_success_submatches_prop}
+% \begin{variable}{\l_regex_success_empty_bool}
+% The booleans \cs{l_regex_success_bool} and
+% \cs{l_regex_success_empty_bool} are true if the current match
+% attempt was successful, and if the match was empty, respectively.
+% The other two variables hold the step number at which the match
+% was successful and a property list of submatches.
+% \begin{macrocode}
+\bool_new:N \l_regex_success_bool
+\bool_new:N \l_regex_success_empty_bool
+\int_new:N \l_regex_success_step_int
+\prop_new:N \l_regex_success_submatches_prop
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+% \end{variable}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_fresh_thread_bool}
+% This boolean marks when the current thread has started from
+% the beginning of the regular expression at this character,
+% in other words, it is true if the current thread has matched
+% an empty string so far (and we only care about this boolean
+% when a thread succeeds, hence matching an empty string overall).
+% \begin{macrocode}
+\bool_new:N \l_regex_fresh_thread_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \subsubsection{Variables used for user functions}
+%
+% \begin{variable}{\g_regex_submatches_seq}
+% This holds temporarily a sequence of submatches,
+% global so that it exits the group.
+% \begin{macrocode}
+\seq_new:N \g_regex_submatches_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_regex_match_count_int}
+% The number of matches found so far is stored
+% in \cs{g_regex_match_count_int}. This is only used
+% in the \cs{regex_count:nnN} functions.
+% \begin{macrocode}
+\int_new:N \g_regex_match_count_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_regex_split_seq}
+% The \cs{regex_split:nnN} function stores its result
+% in that sequence variable before assigning it to the
+% variable provided by the user.
+% \begin{macrocode}
+\seq_new:N \g_regex_split_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_regex_replacement_tl}
+% \begin{variable}{\g_regex_replaced_str}
+% The replacement code stores a processed version
+% of the user's argument in \cs{l_regex_replacement_tl}.
+% The result of the replacement is stored in \cs{g_regex_replaced_str},
+% global to exit the group.
+% \begin{macrocode}
+\tl_new:N \l_regex_replacement_tl
+\tl_new:N \g_regex_replaced_str
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+%
+% \subsection{Helpers}
+%
+% \subsubsection{Toks}
+%
+% \begin{macro}[int]{\s_regex_toks}
+% When performing the matching, the \tn{toks} registers hold submatch
+% information, followed by the instruction for a given state of the NFA.
+% The two parts are separated by \cs{s_regex_toks}.
+% \begin{macrocode}
+\cs_new_eq:NN \s_regex_toks \scan_stop:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_toks_put_left:Nx}
+% \begin{macro}[int]{\regex_toks_put_right:Nx}
+% During the building phase, every \tn{toks} register starts with
+% \cs{s_regex_toks}, and we wish to add \texttt{x}-expanded material
+% to those registers. The expansion is done \enquote{by hand} for
+% optimization (these operations are used quite a lot). When adding
+% material to the left, we define \cs{regex_tmp:w} to remove the
+% \cs{s_regex_toks} marker and put it back to the left of the new
+% material.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_toks_put_left:Nx #1#2
+ {
+ \cs_set_nopar:Npx \regex_tmp:w \s_regex_toks { \s_regex_toks #2 }
+ \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
+ { \exp_after:wN \regex_tmp:w \tex_the:D \tex_toks:D #1 }
+ }
+\cs_new_protected:Npn \regex_toks_put_right:Nx #1#2
+ {
+ \cs_set_nopar:Npx \regex_tmp:w {#2}
+ \tex_toks:D #1 \exp_after:wN
+ { \tex_the:D \tex_toks:D \exp_after:wN #1 \regex_tmp:w }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Interrupting recursions}
+%
+% \begin{macro}[int]{\regex_if_tail_stop:N}
+% \begin{macro}[int]{\regex_if_tail_error:Nn}
+% Test for the end of the \meta{string}, and either stop
+% or cause an error if it is reached.
+% \begin{macrocode}
+\cs_new_eq:NN \regex_if_tail_stop:N \quark_if_recursion_tail_stop:N
+\cs_new_protected_nopar:Npn \regex_if_tail_error:Nn #1#2
+ { \quark_if_recursion_tail_stop_do:Nn #1 { \regex_build_error:n {#2} } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_build_error:n}
+% This macro is called if anything goes wrong when building
+% the NFA corresponding to a given regular expression
+% Negative codes are specific to the \LaTeX3 implementation.
+% Other error codes match with the PCRE codes (not all of
+% the PCRE errors can occur, since some constructions are
+% not supported).
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_error:n #1
+ {
+ \msg_error:nnxx { regex } { build-error } {\int_eval:n{#1}}
+ {
+ \prg_case_int:nnn {#1}
+ {
+ {-999} {File~not~found}
+ {-998} {Unsupported~construct}
+ {-997} {The~regular~expression~is~too~large~(32768~states).}
+ {1} {\iow_char:N\\~at~end~of~pattern }
+% {2} {\iow_char:N\\c~at~end~of~pattern }
+ {4} {Numbers~out~of~order~in~\iow_char:N\{\iow_char\}~quantifier.}
+ {6} {Missing~terminating~\iow_char:N\]~for~character~class }
+ {7} {Invalid~escape~sequence~in~character~class}
+ {8} {Range~out~of~order~in~character~class}
+ {22} {Mismatched~parentheses}
+ {34} {Character~value~in~\iow_char:N\\x{...}~sequence~is~too~large}
+% {44} {Invalid~UTF-8~string}
+% {46} {Malformed~\iow_char:N\\P~or\iow_char:N\\p~sequence}
+% {47} {Unknown~property~after~\iow_char:N\\P~or\iow_char:N\\p}
+% {68} {\iow_char:N\\c~must~be~followed~by~an~ASCII~character}
+ }
+ { Internal~bug. }
+ }
+ }
+\msg_new:nnn { regex } { build-error } { (error~#1): ~ #2 }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Testing characters}
+%
+% \begin{macro}[int]{\regex_break_point:TF}
+% \begin{macro}[int]{\regex_break_true:w,\regex_break_false:w}
+% When testing whether a character of the query string matches
+% a given character class in the regular expression, we often
+% have to test it against several ranges of characters, checking
+% if any one of those matches. This is done with a structure like
+% \begin{quote}
+% \meta{test1} \ldots{} \meta{test$\sb{n}$} \\
+% \cs{regex_break_point:TF} \Arg{true code} \Arg{false code}
+% \end{quote}
+% If any of the tests succeeds, it calls \cs{regex_break_true:w},
+% which cleans up and leaves \meta{true code} in the input stream.
+% Otherwise, \cs{regex_break_point:TF} leaves the \meta{false code}
+% in the input stream.
+% \begin{macrocode}
+\cs_new_nopar:Npn \regex_break_true:w #1 \regex_break_point:TF #2 #3 {#2}
+\cs_new_nopar:Npn \regex_break_false:w #1 \regex_break_point:TF #2 #3 {#3}
+\cs_new_eq:NN \regex_break_point:TF \use_ii:nn
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_item_equal:n,\regex_item_range:nn}
+% \begin{macro}[int]{\regex_item_less:n,\regex_item_more:n}
+% \begin{macro}[int]{\regex_item_neq:n}
+% Simple comparisons triggering \cs{regex_break_true:w} when true.
+% \begin{macrocode}
+\cs_new_nopar:Npn \regex_item_equal:n #1
+ {
+ \if_num:w #1 = \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_range:nn #1 #2
+ {
+ \reverse_if:N \if_num:w #1 > \l_regex_current_char_int
+ \reverse_if:N \if_num:w #2 < \l_regex_current_char_int
+ \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w
+ \fi:
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_less:n #1
+ {
+ \if_num:w #1 > \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_more:n #1
+ {
+ \if_num:w #1 < \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_neq:n #1
+ {
+ \if_num:w #1 = \l_regex_current_char_int
+ \exp_after:wN \regex_break_false:w
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Grabbing digits}
+%
+% \begin{macro}[int]{\regex_get_digits:nw}
+% \begin{macro}[aux]{\regex_get_digits_loop:N,\regex_get_digits_end:w}
+% Grabs digits (of category code other), skipping any intervening
+% space, until encountering a non-digit, and places the result
+% in a brace group after |#1|. This is used when parsing the \texttt{\{}
+% quantifier.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_get_digits:nw #1
+ {
+ \tex_afterassignment:D \regex_tmp:w
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \exp_not:n {#1}
+ { \if_false: } } \fi:
+ \regex_get_digits_aux:N
+ }
+\cs_new_nopar:Npn \regex_get_digits_aux:N #1
+ {
+ \if_num:w 9 < 1 \exp_not:N #1 \exp_stop_f:
+ \else:
+ \if_charcode:w \c_space_token \exp_not:N #1
+ \else:
+ \regex_get_digits_end:w
+ \fi:
+ \fi:
+ #1 \regex_get_digits_aux:N
+ }
+\cs_new_nopar:Npn \regex_get_digits_end:w
+ \fi: \fi: #1 \regex_get_digits_aux:N
+ {
+ \fi: \fi:
+ \if_false: { { \fi: } }
+ #1
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{More char testing}
+%
+% \begin{macro}[EXP,aux]{\regex_aux_char_if_alphanumeric:NTF}
+% \begin{macro}[EXP,aux]{\regex_aux_char_if_special:NTF}
+% These two tests are used in the first pass when parsing a
+% regular expression. That pass is responsible for finding
+% escaped and non-escaped characters, and recognizing which
+% ones have special meanings and which should be interpreted
+% as \enquote{raw} characters. Namely,
+% \begin{itemize}
+% \item alphanumerics are \enquote{raw} if they are not escaped,
+% and may have a special meaning when escaped;
+% \item non-alphanumeric printable ascii characters are \enquote{raw}
+% if they are escaped, and may have a special meaning when not escaped;
+% \item characters other than printable ascii are always \enquote{raw}.
+% \end{itemize}
+% The code is ugly, and highly based on magic numbers and the ascii
+% codes of characters. This is mostly unavoidable for performance
+% reasons: testing for instance with \cs{str_if_contains_char:nN}
+% would be much slower. Maybe the tests can be optimized a little
+% bit more.
+% Here, \enquote{alphanumeric} means \texttt{0}--\texttt{9},
+% \texttt{A}--\texttt{Z}, \texttt{a}--\texttt{z};
+% \enquote{special} character means non-alphanumeric
+% but printable ascii, from space (hex \texttt{20}) to
+% \texttt{del} (hex \texttt{7E}).
+% \begin{macrocode}
+\prg_new_conditional:Npnn \regex_aux_char_if_special:N #1 { TF }
+ {
+ \if_num:w `#1 < 97 \exp_stop_f:
+ \if_num:w `#1 < 58 \exp_stop_f:
+ \if_num:w \int_eval:w (`#1 - \c_eight)/\c_sixteen = \c_two
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w `#1 / 26 = \c_three
+ \prg_return_false:
+ \else:
+ \prg_return_true:
+ \fi:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w `#1 / \c_five = 25 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \fi:
+ }
+\prg_new_conditional:Npnn \regex_aux_char_if_alphanumeric:N #1 { TF }
+ {
+ \if_num:w `#1 < 91 \exp_stop_f:
+ \if_num:w `#1 < 65 \exp_stop_f:
+ \if_num:w \c_nine < 1 #1 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \else:
+ \prg_return_true:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w (`#1-\c_six)/26 = \c_four
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Building}
+%
+% \subsubsection{Helpers for building an NFA}
+%
+% \begin{macro}[int]{\regex_build_new_state:}
+% Here, we add a new state to the NFA. At the end of the building
+% phase, we want every \tn{toks} register to start with
+% \cs{s_regex_toks}, hence initialize the new register appropriately.
+% Then set \cs{l_regex_left/right_state_int} to their new values.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_new_state:
+ {
+ \int_compare:nNnTF \l_regex_max_state_int > {32766}
+ { \regex_build_error:n {-997} }
+ {
+ \int_incr:N \l_regex_max_state_int
+ \tex_toks:D \l_regex_max_state_int { \s_regex_toks }
+ }
+ \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_right_state_int \l_regex_max_state_int
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_transition_aux:NN}
+% \begin{macro}[aux]{\regex_build_transitions_aux:NNNN}
+% These functions create a new state, and put one or two transitions
+% starting from the old current state.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_transition_aux:NN #1#2
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ { #1 { \int_use:N #2 } }
+ }
+\cs_new_protected_nopar:Npn \regex_build_transitions_aux:NNNN #1#2#3#4
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ #1 { \int_use:N #2 }
+ #3 { \int_use:N #4 }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{From regex to NFA: framework}
+%
+% In order for the construction \texttt{ab\string|cd} to work, we enclose
+% the whole pattern within parentheses. These have the added benefit
+% to form a capturing group: hence we get the data of the whole match
+% for free.
+%
+% \begin{macro}[int]{\regex_build:n}
+% First, reset a few variables. Then use the generic framework defined
+% in \pkg{l3str} to parse the regular expression once, recognizing
+% which characters are raw characters, and which have special meanings.
+% The result is stored in \cs{g_str_result_tl}, and can be run directly.
+% The trailing \cs{prg_do_nothing:} ensure that the look-ahead done by
+% some of the operations is harmless.
+% Finally, \cs{regex_build_end:} adds the finishing code
+% (checking that parentheses are properly nested, for instance).
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_build:n #1
+ {
+ \regex_build_setup:
+ \str_aux_escape:NNNn
+ \regex_build_i_unescaped:N
+ \regex_build_i_escaped:N
+ \regex_build_i_raw:N
+ { #1 }
+ \regex_build_open_aux:
+ \g_str_result_tl \prg_do_nothing: \prg_do_nothing:
+ \seq_push:Nn \l_regex_capturing_group_seq { 0 }
+ \regex_build_close_aux: \regex_build_group_:
+ \regex_build_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_i_unescaped:N}
+% \begin{macro}[aux]{\regex_build_i_escaped:N}
+% \begin{macro}[aux]{\regex_build_i_raw:N}
+% The \pkg{l3str} function \cs{str_aux_escape:NNNn} goes through
+% the regular expression and finds the |\a|, |\e|, |\f|, |\n|, |\r|,
+% |\t|, and |\x| escape sequences, then distinguishes three cases:
+% non-escaped characters, escaped characters, and \enquote{raw}
+% characters coming from one of the escape sequences.
+% In the particular case of regular expressions, escaped alphanumerics
+% and non-escaped non-alphanumeric printable ascii characters may have
+% special meanings, while everything else should be treated as a raw
+% character.
+% \begin{macrocode}
+\cs_new_nopar:Npn \regex_build_i_unescaped:N #1
+ {
+ \regex_aux_char_if_special:NTF #1
+ { \exp_not:N \regex_build_control:N #1 }
+ { \exp_not:N \regex_build_raw:N #1 }
+ }
+\cs_new_nopar:Npn \regex_build_i_escaped:N #1
+ {
+ \regex_aux_char_if_alphanumeric:NTF #1
+ { \exp_not:N \regex_build_control:N #1 }
+ { \exp_not:N \regex_build_raw:N #1 }
+ }
+\cs_new_nopar:Npn \regex_build_i_raw:N #1
+ { \exp_not:N \regex_build_raw:N #1 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_default_control:N}
+% If the control character has a particular meaning in regular expressions,
+% the corresponding function is used. Otherwise, it is interpreted as a raw
+% character. The \cs{regex_build_default_raw:N} function is defined later.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_default_control:N #1
+ {
+ \cs_if_exist_use:cF { regex_build_#1: }
+ { \regex_build_default_raw:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_build_setup:}
+% Hopefully, we didn't forget to initialize anything here.
+% The search is not anchored: to acheive that, we insert state(s)
+% responsible for repeating the match attempt on every character
+% of the string: the first state has a free transition to the second
+% state, where the regular expression really begins, and a costly
+% transition to itself, to try again at the next character.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_setup:
+ {
+ \cs_set_eq:NN \regex_build_control:N \regex_build_default_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_build_default_raw:N
+ \int_set_eq:NN \l_regex_capturing_group_int \c_zero
+ \int_zero:N \l_regex_left_state_int
+ \int_zero:N \l_regex_right_state_int
+ \int_zero:N \l_regex_max_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_action_start_wildcard:nn
+ { \int_use:N \l_regex_left_state_int }
+ { \int_use:N \l_regex_right_state_int }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_build_end:}
+% If parentheses are not nested properly, an error is raised,
+% and the correct number of parentheses is closed.
+% After that, we insert an instruction for the match to succeed.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_end:
+ {
+ \seq_if_empty:NF \l_regex_capturing_group_seq
+ {
+ \regex_build_error:n {22}
+ \prg_replicate:nn
+ { \seq_length:N \l_regex_capturing_group_seq } % (
+ { \regex_build_close_aux: \regex_build_group_: }
+ }
+ \regex_toks_put_right:Nx \l_regex_right_state_int
+ { \regex_action_success: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Anchoring and simple assertions}
+%
+% \begin{macro}[int]{\regex_build_A:}
+% \begin{macro}[int]+\regex_build_^:+
+% \begin{macro}[int]{\regex_build_G:}
+% \begin{macro}[aux]{\regex_build_anchor_start:N}
+% Anchoring at the start corresponds to checking that the current
+% character is the first in the string. Anchoring to the beginning
+% of the match attempt uses \cs{l_regex_start_step_int} instead of
+% \cs{c_zero}.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_^: }
+ { \regex_build_anchor_start:N \c_zero }
+\cs_new_protected_nopar:Npn \regex_build_A:
+ { \regex_build_anchor_start:N \c_zero }
+\cs_new_protected_nopar:Npn \regex_build_G:
+ { \regex_build_anchor_start:N \l_regex_start_step_int }
+\cs_new_protected_nopar:Npn \regex_build_anchor_start:N #1
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \int_compare:nNnT {#1} = \l_regex_current_step_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_Z:}
+% \begin{macro}[aux]{\regex_build_z:}
+% \begin{macro}[aux]+\regex_build_$:+
+% This matches the end of the string, marked by a character code of $-1$.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_$: } % $
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \int_compare:nNnT
+ \c_minus_one = \l_regex_current_char_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+\cs_new_eq:Nc \regex_build_Z: { regex_build_$: } %$
+\cs_new_eq:Nc \regex_build_z: { regex_build_$: } %$
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_build_b:}
+% \begin{macro}[int]{\regex_build_B:}
+% \begin{macro}[aux]{\regex_if_word_boundary:TF}
+% Contrarily to |^| and |$|, which could be implemented without
+% really knowing what preceeds in the string, this requires
+% more information. We request it by setting
+% \cs{l_regex_look_behind_bool}. Then the matching code will
+% keep store the characters that were already read, backwards,
+% in \cs{l_regex_look_behind_str}, and we can analyse the first
+% character of that string.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_b:
+ {
+ \bool_set_true:N \l_regex_look_behind_bool
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \regex_if_word_boundary:TF
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ { }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_B:
+ {
+ \bool_set_true:N \l_regex_look_behind_bool
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \regex_if_word_boundary:TF
+ { }
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_if_word_boundary:TF
+ {
+ \tl_if_empty:NTF \l_regex_look_behind_str
+ { \c_regex_w_tl }
+ {
+ \group_begin:
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \int_set:Nn \l_regex_current_char_int
+ { ` \str_head:N \l_regex_look_behind_str }
+ }
+ \regex_tmp:w
+ \c_regex_w_tl
+ \regex_break_point:TF
+ { \group_end: \c_regex_W_tl }
+ { \group_end: \c_regex_w_tl }
+ }
+ \regex_break_point:TF
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Normal character, and simple character classes}
+%
+% \begin{macro}[aux]{\regex_build_default_raw:N}
+% A normal alphanumeric or an escaped non-alphanumeric
+% (actually, any unknown combination) will match itself
+% and the thread will fail otherwise. We prepare
+% \cs{regex_build_tmp_class:n} with the relevant test and
+% commands. The program steps to be inserted in those
+% commands will come as |##1| and |##2|: we don't know
+% yet what those will be before checking for quantifiers.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_default_raw:N #1
+ {
+ \cs_set:Npx \regex_build_tmp_class:n ##1
+ {
+ \exp_not:n { \exp_not:N \if_num:w }
+ \int_value:w `#1 = \l_regex_current_char_int
+ \regex_action_cost:n { ##1 }
+ \exp_not:n { \exp_not:N \fi: }
+ }
+ \regex_build_one_quantifier:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_.:}
+% Similar to \cs{regex_build_default_raw:N} but accepts any character,
+% and refuses $-1$, which marks the end of the string.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_.: }
+ {
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:N \if_num:w \c_minus_one < \l_regex_current_char_int
+ \regex_action_cost:n {##1}
+ \exp_not:N \fi:
+ }
+ \regex_build_one_quantifier:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_d:,\regex_build_D}
+% \begin{macro}[aux]{\regex_build_h:,\regex_build_H}
+% \begin{macro}[aux]{\regex_build_s:,\regex_build_S}
+% \begin{macro}[aux]{\regex_build_v:,\regex_build_V}
+% \begin{macro}[aux]{\regex_build_w:,\regex_build_W}
+% \begin{macro}[aux]{\regex_build_N:}
+% \begin{macro}[aux]{\regex_build_char_type:N}
+% The constants \cs{c_regex_d_tl}, \emph{etc.} hold
+% a list of tests which match the corresponding character
+% class, and jump to the \cs{regex_break_point:TF} marker.
+% As for a normal character, we check for quantifiers.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_char_type:N #1
+ {
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:N #1
+ \exp_not:N \regex_break_point:TF
+ { \regex_action_cost:n {##1} }
+ { }
+ }
+ \regex_build_one_quantifier:
+ }
+\tl_map_inline:nn { dDhHsSvVwWN }
+ {
+ \cs_new_protected_nopar:cpx { regex_build_#1: }
+ {
+ \exp_not:N \regex_build_char_type:N
+ \exp_not:c { c_regex_#1_tl }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Character classes}
+%
+% \begin{macro}[aux]{\regex_build_[:}
+% This starts a class. The code for the class is collected
+% in \cs{l_regex_class_tl}. The first character is special.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_[: }
+ {
+ \tl_clear:N \l_regex_class_tl
+ \cs_set_eq:NN \regex_build_control:N \regex_class_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_class_raw:N
+ \regex_class_first:NN
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_class_control:N}
+% This function is similar to \cs{regex_build_control:N}. If the control
+% character has a meaning in character classes, call the corresponding
+% function, otherwise, treat it as a raw character, with the
+% \cs{regex_class_raw:N} function, defined later.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_class_control:N #1
+ {
+ \cs_if_exist_use:cF { regex_class_#1: }
+ { \regex_class_raw:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_class_]:}
+% If \texttt{]} appears as the first item of a class, then
+% it doesn't end the class. Otherwise, it's the end,
+% act just as for a single character, but with a more
+% complicated test. And restore \cs{regex_build_control:N}
+% and \cs{regex_build_raw:N}.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_class_]: }
+ {
+ \tl_if_empty:NTF \l_regex_class_tl %[
+ { \regex_class_raw:N ] }
+ {
+ \cs_set_eq:NN \regex_build_control:N \regex_build_default_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_build_default_raw:N
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:o \l_regex_class_tl
+ \bool_if:NTF \l_regex_class_bool
+ {
+ \exp_not:N \regex_break_point:TF
+ { \regex_action_cost:n {##1} }
+ { }
+ }
+ {
+ \exp_not:N \regex_break_point:TF
+ { }
+ { \regex_action_cost:n {##1} }
+ }
+ }
+ \regex_build_one_quantifier:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_class_first:NN}
+% If the first non-space character is |^|, then the class is inverted.
+% We keep track of this in \cs{l_regex_class_bool}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_class_first:NN #1#2
+ {
+ \str_if_eq:nnTF {#1#2} { \regex_build_control:N ^ }
+ { \bool_set_false:N \l_regex_class_bool }
+ {
+ \bool_set_true:N \l_regex_class_bool
+ #1 #2
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_class_raw:N}
+% \begin{macro}[aux]{\regex_class_single:N}
+% Most characters are treated here. We look ahead for an unescaped dash.
+% If there is none, then the character matches itself.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_class_raw:N #1#2#3
+ {
+ \str_if_eq:nnTF {#2#3} { \regex_build_control:N - }
+ { \regex_class_range:Nw #1 }
+ {
+ \regex_class_single:N #1
+ #2 #3
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_class_single:N #1
+ {
+ \tl_put_right:Nx \l_regex_class_tl
+ { \exp_not:N \regex_item_equal:n { \int_value:w `#1 } }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_class_range:Nw}
+% \begin{macro}[aux]{\regex_class_range_put:NN}
+% If the character is followed by a dash, we look for
+% the end-point of the range. For \enquote{raw} characters,
+% that's simply |#3|. Most \enquote{control} characters also
+% have no meaning, and can serve as an end-point, but those
+% with a meaning interrupt the range.
+% In the case of a true range, check whether the end-points
+% are in the right order, and optimize in the case of equal
+% end-points.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_class_range:Nw #1#2#3
+ {
+ \token_if_eq_meaning:NNTF #2 \regex_build_control:N
+ {
+ \cs_if_exist:cTF { regex_class_#3: }
+ {
+ \regex_class_single:N #1
+ \regex_class_single:N -
+ #2#3
+ }
+ { \regex_class_range_put:NN #1#3 }
+ }
+ { \regex_class_range_put:NN #1#3 }
+ }
+\cs_new_protected_nopar:Npn \regex_class_range_put:NN #1#2
+ {
+ \if_num:w `#1 > `#2 \exp_stop_f:
+ \regex_build_error:n {8}
+ \else:
+ \tl_put_right:Nx \l_regex_class_tl
+ {
+ \if_num:w `#1 = `#2 \exp_stop_f:
+ \exp_not:N \regex_item_equal:n
+ \else:
+ \exp_not:N \regex_item_range:nn { \int_value:w `#1 }
+ \fi:
+ { \int_value:w `#2 }
+ }
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_class_d:,\regex_class_D:}
+% \begin{macro}[aux]{\regex_class_h:,\regex_class_H:}
+% \begin{macro}[aux]{\regex_class_s:,\regex_class_S:}
+% \begin{macro}[aux]{\regex_class_v:,\regex_class_V:}
+% \begin{macro}[aux]{\regex_class_w:,\regex_class_W:}
+% Similar to \cs{regex_class_single:N}, adding the appropriate
+% ranges of characters to the class. The token lists are not
+% expanded because it is more memory efficient, with a tiny
+% overhead on execution.
+% \begin{macrocode}
+\tl_map_inline:nn { dDhHsSvVwWN }
+ {
+ \cs_new_protected_nopar:cpx { regex_class_#1: }
+ {
+ \tl_put_right:Nn \exp_not:N \l_regex_class_tl
+ { \exp_not:c { c_regex_#1_tl } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Quantifiers}
+%
+% \begin{macro}[int]{\regex_build_quantifier:w}
+% This looks ahead and finds any quantifier (control character
+% equal to either of |?+*{|). ^^A}
+% When all characters for the quantifier are found, the corresponding
+% function is called.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_quantifier:w #1#2
+ {
+ \token_if_eq_meaning:NNTF #1 \regex_build_control:N
+ {
+ \cs_if_exist_use:cF { regex_build_quantifier_#2:w }
+ {
+ \regex_build_quantifier_end:n { }
+ #1 #2
+ }
+ }
+ {
+ \regex_build_quantifier_end:n { }
+ #1 #2
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_quantifier_?:w}
+% \begin{macro}[aux]{\regex_build_quantifier_*:w}
+% \begin{macro}[aux]{\regex_build_quantifier_+:w}
+% For each \enquote{basic} quantifier, |?|, |*|, |+|, feed the correct
+% arguments to \cs{regex_build_quantifier_aux:nnNN}.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_quantifier_?:w }
+ { \regex_build_quantifier_aux:nnNN { } { ? } }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_*:w }
+ { \regex_build_quantifier_aux:nnNN { } { * } }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_+:w }
+ { \regex_build_quantifier_aux:nnNN { } { + } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_quantifier_aux:nnNN}
+% Once the \enquote{main} quantifier (\texttt{?}, \texttt{*},
+% \texttt{+} or a braced construction) is found, we check
+% whether it is lazy (followed by a question mark),
+% and calls the appropriate function. Here |#1| holds some extra
+% arguments that the final function needs in the case of braced
+% constructions, and is empty otherwise.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_quantifier_aux:nnNN #1#2#3#4
+ {
+ \str_if_eq:nnTF { #3 #4 } { \regex_build_control:N ? }
+ { \regex_build_quantifier_end:n { #2 #4 } #1 }
+ {
+ \regex_build_quantifier_end:n { #2 } #1
+ #3 #4
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]+\regex_build_quantifier_{:w+ ^^A}
+% \begin{macro}[aux]{\regex_build_quantifier_lbrace:n}
+% \begin{macro}[aux]{\regex_build_quantifier_lbrace:nw}
+% \begin{macro}[aux]{\regex_build_quantifier_lbrace:nnw}
+% Three possible syntaxes: \texttt{\{\meta{int}\}},
+% \texttt{\{\meta{int},\}}, or \texttt{\{\meta{int},\meta{int}\}}.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_quantifier_ \c_lbrace_str :w }
+ { \regex_get_digits:nw { \regex_build_quantifier_lbrace:n } }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_lbrace:n #1
+ {
+ \tl_if_empty:nTF {#1}
+ {
+ \regex_build_quantifier_end:n { }
+ \exp_after:wN \regex_build_raw:N \c_lbrace_str
+ }
+ { \regex_build_quantifier_lbrace:nw {#1} }
+ }
+\cs_new_protected_nopar:Npx \regex_build_quantifier_lbrace:nw #1#2#3
+ {
+ \exp_not:N \prg_case_str:nnn { #2 #3 }
+ {
+ { \exp_not:N \regex_build_control:N , }
+ {
+ \exp_not:N \regex_get_digits:nw
+ { \exp_not:N \regex_build_quantifier_lbrace:nnw {#1} }
+ }
+ { \exp_not:N \regex_build_control:N \c_rbrace_str }
+ { \exp_not:N \regex_build_quantifier_end:n {n} {#1} }
+ }
+ {
+ \exp_not:N \regex_build_quantifier_end:n { }
+ \exp_not:N \regex_build_raw:N \c_lbrace_str #1#2
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_lbrace:nnw #1#2#3
+ {
+ \str_if_eq:xxTF { \exp_not:N #3 } { \c_rbrace_str }
+ {
+ \tl_if_empty:nTF {#2}
+ { \regex_build_quantifier_aux:nnN { {#1} {\c_max_int} } {nn} }
+ {
+ \int_compare:nNnT {#1} > {#2}
+ { \regex_build_error:n {4} }
+ \regex_build_quantifier_aux:nnN { {#1} {#2} } {nn}
+ }
+ }
+ {
+ \regex_build_quantifier_end:n { }
+ \use:x
+ {
+ \exp_not:n { \exp_args:No \tl_map_function:nN }
+ { \c_lbrace_str #1 #2 , }
+ \regex_build_raw:N
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_quantifier_end:n}
+% When all quantifiers are found, we will call the relevant
+% \cs{regex_build_one/group_\meta{quantifiers}:} function.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_quantifier_end:n #1
+ { \use:c { regex_build_ \l_regex_one_or_group_tl _ #1 : } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Quantifiers for one character or character class}
+%
+% \begin{macro}[aux]{\regex_build_one_quantifier:}
+% Used for one single character, or a character class.
+% Contrarily to \cs{regex_build_group_quantifier:},
+% we don't need to keep track of submatches, and no thread
+% can be created within one repetition, so things are relatively easy.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_one_quantifier:
+ {
+ \tl_set:Nx \l_regex_one_or_group_tl { one }
+ \regex_build_quantifier:w
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_one_:}
+% If no quantifier is found, then the character or character class
+% should just be built into a transition from the current
+% \enquote{right} state to a new state.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_one_:
+ {
+ \regex_build_transition_aux:NN
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_one_?:}
+% \begin{macro}[aux]{\regex_build_one_??:}
+% The two transitions are a costly transition controlled by
+% the character class, and a free transition, both going to
+% a common new state. The only difference between the greedy
+% and lazy operators is the order of transitions.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_one_?: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_??: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_one_*:}
+% \begin{macro}[aux]{\regex_build_one_*?:}
+% Build a costly transition going from the current state to itself,
+% and a free transition moving to a new state.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_one_*: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_build_tmp_class:n \l_regex_left_state_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_*?: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_build_tmp_class:n \l_regex_left_state_int
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_one_+:}
+% \begin{macro}[aux]{\regex_build_one_+?:}
+% Build a transition from the current state to a new state,
+% controlled by the character class, then build two transitions
+% from this new state to the original state (for repetition)
+% and to another new state (to move on to the rest of the pattern).
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_one_+: }
+ {
+ \regex_build_one_:
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_tmpa_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_+?: }
+ {
+ \regex_build_one_:
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_tmpa_int
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_one_n:}
+% \begin{macro}[aux]{\regex_build_one_n?:}
+% This function is called in case the syntax is
+% \texttt{\{\meta{int}\}}. Greedy and lazy operators
+% are identical, since the number of repetitions is fixed.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_one_n: #1
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_right_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_tmpa_int
+ { %^^A safe \if nesting?
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \else:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_build_tmp_class:n
+ { \int_use:N \l_regex_tmpa_int }
+ }
+ }
+\cs_new_eq:cN { regex_build_one_n?: } \regex_build_one_n:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_one_nn:}
+% \begin{macro}[aux]{\regex_build_one_nn?:}
+% \begin{macro}[aux]{\regex_build_one_nn_aux:nn}
+% This function is called when the syntax is either
+% \texttt{\{\meta{int},\}} or \texttt{\{\meta{int},\meta{int}\}}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_one_nn: #1#2
+ {
+ \regex_build_one_nn_aux:nn {#1}
+ {
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \regex_action_repeat_copy:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \fi:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_nn?: } #1#2
+ {
+ \regex_build_one_nn_aux:nn {#1}
+ {
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \fi:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_one_nn_aux:nn #1#2
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_right_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_tmpa_int
+ {
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \else:
+ #2
+ \exp_not:N \fi:
+ }
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_build_tmp_class:n
+ { \int_use:N \l_regex_tmpa_int }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Groups and alternation}
+%
+% We support the syntax \texttt{(\meta{expr1}|\ldots{}%^^A
+% |\meta{expr$\sb{n}$})\meta{quantifier}} for alternations.
+%
+% \begin{macro}[aux]{\regex_build_(:, \regex_build_):}
+% \begin{macro}[aux]{\regex_build_open_aux:}
+% \begin{macro}[aux]+\regex_build_|:+
+% \begin{macro}[aux]{\regex_build_begin_alternation:,
+% \regex_build_end_alternation:}
+% Grouping and alternation go together.
+% \begin{itemize}
+% \item Allocate the next available number for the end vertex
+% of the alternation/group and store it on a stack (so that nested
+% alternations work).
+% \item Put free transitions to separate all cases of the alternation.
+% \item Build each branch separately, and merge them to the common
+% end-node.
+% \item Test for a quantifier, and if needed, transfer the initial
+% vertex to a new vertex.
+% \end{itemize}
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_(: } #1#2
+ {
+ \str_if_eq:nnTF { #1 #2 } { \regex_build_control:N ? }
+ { \regex_build_special_group:NN }
+ {
+ \int_incr:N \l_regex_capturing_group_int
+ \seq_push:Nx \l_regex_capturing_group_seq
+ { \int_use:N \l_regex_capturing_group_int }
+ \regex_build_open_aux:
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_open_aux:
+ {
+ \regex_build_new_state:
+ \seq_push:Nx \l_regex_left_state_seq
+ { \int_use:N \l_regex_left_state_int }
+ \seq_push:Nx \l_regex_right_state_seq
+ { \int_use:N \l_regex_right_state_int }
+ \regex_build_begin_alternation:
+ }
+\cs_new_protected_nopar:cpn { regex_build_|: }
+ {
+ \regex_build_end_alternation:
+ \regex_build_begin_alternation:
+ }
+\cs_new_protected_nopar:cpn { regex_build_): }
+ {
+ \seq_if_empty:NTF \l_regex_capturing_group_seq
+ { \regex_build_error:n {22} }
+ {
+ \regex_build_close_aux:
+ \regex_build_group_quantifier:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_close_aux:
+ {
+ \regex_build_end_alternation:
+ \seq_pop:NN \l_regex_left_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_left_state_int \l_regex_tmpa_tl
+ \seq_pop:NN \l_regex_right_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_right_state_int \l_regex_tmpa_tl
+ }
+% \end{macrocode}
+% Building each branch.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_begin_alternation:
+ {
+ \regex_build_new_state:
+ \seq_get:NN \l_regex_left_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_left_state_int \l_regex_tmpa_tl
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+\cs_new_protected_nopar:Npn \regex_build_end_alternation:
+ {
+ \seq_get:NN \l_regex_right_state_seq \l_regex_tmpa_tl
+ \regex_toks_put_right:Nx \l_regex_right_state_int
+ { \regex_action_free:n { \l_regex_tmpa_tl } }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\regex_build_special_group:NN}
+% Same method as elsewhere: if the combination |(?#1| ^^A )
+% is known, then use that. Otherwise, treat the question mark
+% as if it had been escaped.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_special_group:NN #1#2
+ {
+ \cs_if_exist_use:cF { regex_build_special_group_\token_to_str:N #2 : }
+ {
+ \regex_build_error:n { -998 }
+ \regex_build_control:N ( % )
+ \regex_build_raw:N ?
+ #1 #2
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\regex_build_special_group_::}
+% Non-capturing groups are like capturing groups, except that
+% we set the group id to \texttt{*}, which will then inhibit
+% submatching in \cs{regex_build_group_submatches:NN}.
+% The group number is not increased.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_special_group_:: }
+ {
+ \seq_push:Nx \l_regex_capturing_group_seq { * }
+ \regex_build_open_aux:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Quantifiers for groups}
+%
+% \begin{macro}[aux]{\regex_build_group_quantifier:}
+% Used for one group. We need to keep track of submatches,
+% threads can be created within one repetition, so things are hard.
+% The code for the group that was just built starts
+% at \cs{l_regex_left_state_int} and ends at
+% \cs{l_regex_right_state_int}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_group_quantifier:
+ {
+ \tl_set:Nn \l_regex_one_or_group_tl { group }
+ \regex_build_quantifier:w
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_group_submatches:NN}
+% Once the quantifier is found by \cs{regex_build_quantifier:w},
+% we insert the code for tracking submatches.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_group_submatches:NN #1#2
+ {
+ \seq_pop:NN \l_regex_capturing_group_seq \l_regex_tmpa_tl
+ \str_if_eq:xxF { \l_regex_tmpa_tl } { * }
+ {
+ \regex_toks_put_left:Nx #1
+ { \regex_action_submatch:n { \l_regex_tmpa_tl < } }
+ \regex_toks_put_left:Nx #2
+ { \regex_action_submatch:n { \l_regex_tmpa_tl > } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_group_:}
+% When there is no quantifier, the group is simply inserted as is,
+% and we only need to track submatches.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_group_:
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_right_state_int
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_group_shift:N}
+% Most quantifiers require to add an extra state before the group.
+% This is done by shifting the current contents of the \cs{tex_toks:D}
+% \cs{l_regex_tmpa_int} to a new state.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_group_shift:N #1
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_new_state:
+ \tex_toks:D \l_regex_right_state_int = \tex_toks:D \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ { \s_regex_toks #1 { \int_use:N \l_regex_right_state_int } }
+ }
+ \regex_build_group_submatches:NN
+ \l_regex_right_state_int \l_regex_left_state_int
+ \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_group_qs_aux:NN}
+% \begin{macro}[aux]{\regex_build_group_?:}
+% \begin{macro}[aux]{\regex_build_group_??:}
+% \begin{macro}[aux]{\regex_build_group_*:}
+% \begin{macro}[aux]{\regex_build_group_*?:}
+% Shift the state at which the group begins using
+% \cs{regex_build_group_shift:N}, then add two transitions.
+% The first transition is taken once the group has been
+% traversed: in the case of \texttt{?} and \texttt{??},
+% we should exit by going to \cs{l_regex_right_state_int},
+% while for \texttt{*} and \texttt{*?} we loop by going to
+% \cs{l_regex_tmpa_int}.
+% The second transition corresponds to skipping the group;
+% it has lower priority (\texttt{put_right}) for greedy
+% operators, and higher priority (\texttt{put_left}) for
+% lazy operators.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_group_qs_aux:NN #1#2
+ {
+ \regex_build_group_shift:N \regex_action_free:n
+ \regex_build_transition_aux:NN \regex_action_free:n #1
+ #2 \l_regex_tmpa_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_?: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_right_state_int \regex_toks_put_right:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_??: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_right_state_int \regex_toks_put_left:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_*: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_tmpa_int \regex_toks_put_right:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_*?: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_tmpa_int \regex_toks_put_left:Nx
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_group_+:}
+% \begin{macro}[aux]{\regex_build_group_+?:}
+% Insert the submatch tracking code, then add two transitions
+% from the current state to the left end of the group (repeating the group),
+% and to a new state (to carry on with the rest of the regular expression).
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { regex_build_group_+: }
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_tmpa_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_+?: }
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_tmpa_int
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_group_n:}
+% \begin{macro}[aux]{\regex_build_group_n?:}
+% These functions are called in case the syntax is
+% \texttt{\{\meta{int}\}}. Greedy and lazy operators
+% are identical, since the number of repetitions is fixed.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_group_n: #1
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ }
+ }
+\cs_new_eq:cN { regex_build_group_n?: } \regex_build_group_n:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_build_group_nn:}
+% \begin{macro}[aux]{\regex_build_group_nn?:}
+% These functions are called when the syntax is either
+% \texttt{\{\meta{int},\}} or \texttt{\{\meta{int},\meta{int}\}}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_build_group_nn: #1#2
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \fi:
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_nn?: } #1#2
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \fi:
+ \exp_not:N \fi:
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Matching}
+%
+% \subsubsection{Use of \TeX{} registers when matching}
+%
+% The first step in matching a regular expression is to build
+% the corresponding NFA and store its states in the \tn{toks}
+% registers. Then loop through the query string one character
+% (one \enquote{step}) at a time, exploring in parallel every
+% possible path through the NFA. We keep track of an array of
+% the states currently \enquote{active}. More precisely,
+% \tn{skip} registers hold the state numbers to be considered
+% when the next character of the string is read.
+%
+% At every step, we unpack that array of active states and
+% empty it. Then loop over all active states, and perform the
+% instruction at that state of the NFA. This can involve
+% \enquote{free} transitions to other states, or transitions
+% which \enquote{consume} the current character. For free
+% transitions, the instruction at the new state of the NFA is
+% performed. When a transition consumes a character, the new
+% state is put in the array of \tn{skip} registers: it will
+% be active again when the next character is read.
+%
+% If two paths through the NFA \enquote{collide} in the sense
+% that they reach the same state when reading a given
+% character, then any future execution will be identical for
+% both. Hence, it is indeed enough to keep track of which
+% states are active. [In the presence of back-references, the
+% future execution is affected by how the previous match took
+% place; this is why we cannot support those non-regular
+% features.]
+%
+% Many of the functions require extracting the submatches for
+% the \enquote{best} match. Execution paths through the NFA
+% are ordered by precedence: for instance, the regular
+% expression \texttt{a?} creates two paths, matching either
+% an empty string or a single \texttt{a}; the path matching
+% an \texttt{a} has higher precedence. When two paths collide,
+% the path with the highest precedence is kept, and the other
+% one is discarded. The submatch information for a given path
+% is stored at the start of the \tn{toks} register which
+% holds the state at which that path currently is.
+%
+% Deciding to store the submatch information in \tn{toks}
+% registers alongside with states of the NFA unfortunately
+% implies some shuffling around. The two other options are to
+% store the submatch information in one control sequence per
+% path, which wastes csnames, or to store all of the submatch
+% information in one property list, which turns out to be too
+% slow. A tricky aspect of submatch tracking is to know when
+% to get rid of submatch information. This naturally happens
+% when submatch information is stored in \tn{toks} registers:
+% if the information is not moved, it will be overwritten
+% later.
+%
+% The presence of $\epsilon$-transitions (transitions which
+% consume no character) leads to potential infinite loops;
+% for instance the regular expression |(a??)*| could lead to
+% an infinite recursion, where |a??| matches no character, |*|
+% loops back to the start of the group, and |a??| matches no
+% character again. Therefore, we need to keep track of the
+% states of the NFA visited at the current step. More
+% precisely, a state is marked as \enquote{visited} if the
+% instructions for that state have been inserted in the input
+% stream, by setting the corresponding \tn{dimen} register to
+% a value which uniquely identifies at which step it was last
+% inserted.
+%
+% The current approach means that stretch and shrink components
+% of \tn{skip} registers,
+% as well as all \tn{muskip} registers are unused. It could seem that
+% \tn{count} registers are also free for use, but we still want to be
+% able to safely use integers, which are implemented as \tn{count}
+% registers.
+%
+% \subsubsection{Helpers for running the NFA}
+%
+% \begin{macro}[aux]{\regex_if_state_free:nT}
+% A state is free if it is not marker as taken, namely
+% if the corresponding \tn{dimen} register is $0\mathtt{sp}$
+% rather than $1\mathtt{sp}$.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_if_state_free:nT #1
+ {
+ \if_num:w \tex_dimen:D #1 = \l_regex_unique_step_int
+ \exp_after:wN \use_none:n
+ \else:
+ \exp_after:wN \use:n
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_store_state:n}
+% Put the given state in the array of \tn{skip} registers.
+% This is done by increasing the pointer
+% \cs{l_regex_max_index_int}, and converting the integer
+% to a dimension (suitable for a \tn{skip} assignment) in
+% scaled points.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_store_state:n #1
+ {
+ \int_incr:N \l_regex_max_index_int
+ \tex_skip:D \l_regex_max_index_int #1 sp \scan_stop:
+ \regex_store_submatches:n {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_state_use:}
+% \begin{macro}[int]{\regex_state_use_submatches:}
+% \begin{macro}[aux]{\regex_state_use_aux:n}
+% \begin{macro}[aux]{\regex_state_use_aux_ii:w}
+% Use a given program instruction, unless it has already been
+% executed at this step. The \tn{toks} registers begin with
+% some submatch information, ignored by \cs{regex_state_use:},
+% but not by \cs{regex_state_use_submatches:}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_state_use_submatches:
+ { \regex_state_use_aux:n { } }
+\cs_new_protected_nopar:Npn \regex_state_use:
+ { \regex_state_use_aux:n { \exp_after:wN \regex_state_use_aux_ii:w } }
+\cs_new:Npn \regex_state_use_aux_ii:w #1 \s_regex_toks { }
+\cs_new_protected:Npn \regex_state_use_aux:n #1
+ {
+ \regex_if_state_free:nT { \l_regex_current_state_int }
+ {
+ \tex_dimen:D \l_regex_current_state_int
+ = \l_regex_unique_step_int sp \scan_stop:
+ #1 \tex_the:D \tex_toks:D \l_regex_current_state_int \scan_stop:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Submatch tracking when running the NFA}
+%
+% \begin{macro}[int]{\regex_disable_submatches:}
+% Some user functions don't require tracking submatches.
+% We get a performance improvement by simply defining the
+% relevant functions to remove their argument and do nothing
+% with it.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_disable_submatches:
+ {
+ \cs_set_eq:NN \regex_state_use_submatches: \regex_state_use:
+ \cs_set_eq:NN \regex_store_submatches:n
+ \regex_protected_use_none:n
+ \cs_set_eq:NN \regex_action_submatches:n
+ \regex_protected_use_none:n
+ }
+\cs_new_protected:Npn \regex_protected_use_none:n #1 { }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_store_submatches:n}
+% \begin{macro}[aux]{\regex_store_submatches_aux:Nw}
+% \begin{macro}[aux]{\regex_store_submatches_aux_ii:wnnwwn}
+% The submatch information pertaining to one given thread is moved
+% from state to state as we execute the NFA.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_store_submatches:n #1
+ {
+ \exp_after:wN \regex_store_submatches_aux:Nw
+ \exp_after:wN \l_regex_current_submatches_prop
+ \tex_the:D \tex_toks:D #1 \scan_stop: \q_stop
+ { #1 }
+ }
+\cs_new_protected:Npn \regex_store_submatches_aux:Nw #1 #2 \s_regex_toks
+ {
+ \exp_args:No \regex_store_submatches_aux_ii:wnnwwn { #1 }
+ #2
+ \regex_state_submatches:nn { \c_minus_one } { \q_prop }
+ \s_regex_toks
+ }
+\cs_new_protected:Npn \regex_store_submatches_aux_ii:wnnwwn
+ #1 \regex_state_submatches:nn #2#3 #4 \s_regex_toks #5 \q_stop #6
+ {
+ \tex_toks:D #6 \exp_after:wN
+ {
+ \exp_after:wN \regex_state_submatches:nn \exp_after:wN
+ { \int_value:w \int_eval:w \l_regex_unique_step_int + \c_one }
+ { #1 }
+ \regex_state_submatches:nn {#2} {#3}
+ \s_regex_toks
+ #5
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_state_submatches:nn}
+% This function is inserted by \cs{regex_store_submatches:n}
+% in the \tn{toks} register holding a given state, and it is
+% performed when the state is used.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_state_submatches:nn #1#2
+ {
+ \if_num:w #1 = \l_regex_unique_step_int
+ \tl_set:Nn \l_regex_current_submatches_prop {#2}
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Matching: framework}
+%
+% \begin{macro}[int]{\regex_match:n}
+% Store the query string in \cs{l_regex_query_str}.
+% Then reset a few variables which should be set only once,
+% before the first match, even in the case of multiple matches.
+% Then run the NFA (\cs{regex_match_once:} matches multiple times
+% when appropriate).
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_match:n #1
+ {
+ \tl_set:Nx \l_regex_query_str { \tl_to_other_str:n {#1} }
+ \regex_match_initial_setup:
+ \regex_match_once:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_match_once:}
+% \begin{macro}[aux]{\regex_match_once_aux:}
+% After setting up more variables in \cs{regex_match_setup:},
+% skip the \cs{l_regex_start_step_int} first characters of the
+% query string, and loop over it.
+% If there was a match, use the token list \cs{l_regex_every_match_tl},
+% which may call \cs{regex_match_once:} to achieve multiple matches.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_match_once:
+ {
+ \regex_match_setup:
+ \exp_after:wN \regex_match_once_aux: \l_regex_query_str
+ \q_recursion_tail \q_recursion_stop
+ \bool_if:NT \l_regex_success_bool { \l_regex_every_match_tl }
+ }
+\cs_new_protected_nopar:Npn \regex_match_once_aux:
+ { \str_skip_do:nn { \l_regex_start_step_int } { \regex_match_loop:N } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_match_initial_setup:}
+% This function holds the setup that should be done
+% only once for one given pattern matching on a given
+% string. It is called only once for the whole string.
+% On the other hand, \cs{regex_match_setup:}
+% is called for every match in the string in case of
+% repeated matches, and \cs{regex_match_loop_setup:}
+% is called at every step.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_match_initial_setup:
+ {
+ \tl_clear:N \l_regex_look_behind_str
+ \prg_stepwise_inline:nnnn {1} {1} { \l_regex_max_state_int }
+ { \tex_dimen:D ##1 \c_minus_one sp \scan_stop: }
+ \int_set_eq:NN \l_regex_unique_step_int \c_minus_one
+ \int_set_eq:NN \l_regex_start_step_int \c_minus_one
+ \int_set_eq:NN \l_regex_current_step_int \c_zero
+ \int_set_eq:NN \l_regex_success_step_int \c_zero
+ \bool_set_false:N \l_regex_success_empty_bool
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_match_setup:}
+% Every time a match starts, \cs{regex_match_setup:} resets
+% a few variables.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_match_setup:
+ {
+ \prop_clear:N \l_regex_current_submatches_prop
+ \bool_if:NTF \l_regex_success_empty_bool
+ { \cs_set_eq:NN \regex_last_match_empty:F \regex_last_match_empty_yes:F }
+ { \cs_set_eq:NN \regex_last_match_empty:F \regex_last_match_empty_no:F }
+ \int_set_eq:NN \l_regex_start_step_int \l_regex_success_step_int
+ \int_set_eq:NN \l_regex_current_step_int \l_regex_start_step_int
+ \int_decr:N \l_regex_current_step_int
+ \bool_set_false:N \l_regex_success_bool
+ \int_zero:N \l_regex_max_index_int
+ \regex_store_state:n {1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_match_loop_setup:}
+% This is called for every character in the string.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_match_loop_setup:
+ {
+ \int_incr:N \l_regex_current_step_int
+ \int_incr:N \l_regex_unique_step_int
+ \bool_set_false:N \l_regex_fresh_thread_bool
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\s_regex_step}
+% \begin{macro}[aux]{\regex_break_step:w}
+% When a thread succeeds, all threads with lower precedence
+% can be ignored, and the next character should be read.
+% This is done by skipping to \cs{s_regex_step}. This marker
+% does nothing if no thread succeeded at this step.
+% \begin{macrocode}
+\cs_new_eq:NN \s_regex_step \scan_stop:
+\cs_new:Npn \regex_break_step:w #1 \s_regex_step { }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_match_loop:N}
+% \begin{macro}[aux]{\regex_match_one_index:n}
+% \begin{macro}[aux]{\regex_match_one_index_aux:nn}
+% Setup what needs to be reset at every character,
+% then set \cs{l_regex_current_char_int} to the
+% character code of the character that is read
+% (and $-1$ for the end of the string), and loop
+% over the elements of the \tn{skip} array. Then repeat.
+% There are a couple of tests to stop reading the string
+% when no active state is left, or when the end is reached.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_match_loop:N #1
+ {
+ \regex_match_loop_setup:
+ \token_if_eq_meaning:NNTF #1 \q_recursion_tail
+ { \int_set_eq:NN \l_regex_current_char_int \c_minus_one }
+ { \int_set:Nn \l_regex_current_char_int {`#1} }
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \int_zero:N \l_regex_max_index_int
+ \prg_stepwise_function:nnnN
+ {1} {1} { \l_regex_max_index_int }
+ \regex_match_one_index:n
+ }
+ \regex_tmp:w
+ \s_regex_step
+ \if_num:w \l_regex_max_index_int = \c_zero
+ \exp_after:wN \use_none_delimit_by_q_recursion_stop:w
+ \fi:
+ \quark_if_recursion_tail_stop:N #1
+ \bool_if:NT \l_regex_look_behind_bool
+ { \tl_put_left:Nx \l_regex_look_behind_str {#1} }
+ \regex_match_loop:N
+ }
+\cs_new_nopar:Npn \regex_match_one_index:n #1
+ {
+ \regex_match_one_index_aux:n { \int_value:w \tex_skip:D #1 }
+ }
+\cs_new_protected_nopar:Npn \regex_match_one_index_aux:n #1
+ {
+ \int_set:Nn \l_regex_current_state_int {#1}
+ \prop_clear:N \l_regex_current_submatches_prop
+ \regex_state_use_submatches:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Actions when matching}
+%
+% \begin{macro}[aux]{\regex_action_start_wildcard:nn}
+% The search is made unanchored at the start by putting
+% a free transition to the real start of the NFA, and a
+% costly transition to the same state, waiting for the
+% next character in the query string. This combination
+% could be reused (with some changes). We sometimes need
+% to know that the match for a given thread starts at
+% this character. For that, we use the boolean
+% \cs{l_regex_fresh_thread_bool}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_action_start_wildcard:nn #1#2
+ {
+ \bool_set_true:N \l_regex_fresh_thread_bool
+ \regex_action_free:n {#2}
+ \bool_set_false:N \l_regex_fresh_thread_bool
+ \regex_action_cost:n {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_action_cost:n}
+% A transition which consumes the current character and moves
+% to state |#1|.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_action_cost:n #1
+ { \regex_store_state:n {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_action_success:}
+% There is a successful match when an execution path reaches
+% the end of the regular expression. Then store the current
+% step and submatches. The current step is then interrupted,
+% and only paths with higher precedence are pursued further.
+% The values stored here may be overwritten by a later success
+% of a path with higher precedence.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_action_success:
+ {
+ \regex_last_match_empty:F
+ {
+ \bool_set_true:N \l_regex_success_bool
+ \bool_set_eq:NN \l_regex_success_empty_bool
+ \l_regex_fresh_thread_bool
+ \int_set_eq:NN \l_regex_success_step_int
+ \l_regex_current_step_int
+ \prop_set_eq:NN \l_regex_success_submatches_prop
+ \l_regex_current_submatches_prop
+ \regex_break_step:w
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_action_free:n}
+% To copy a thread, check whether the program state has already
+% been used at this character. If not, store submatches in the
+% new state, and insert the instructions for that state in the
+% input stream.
+% Then restore the old value of \cs{l_regex_current_state_int}
+% and of the current submatches.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_action_free:n #1
+ {
+ \regex_if_state_free:nT {#1}
+ {
+ \use:x
+ {
+ \int_set:Nn \l_regex_current_state_int {#1}
+ \regex_store_submatches:n { \l_regex_current_state_int }
+ \regex_state_use:
+ \int_set:Nn \l_regex_current_state_int
+ { \int_use:N \l_regex_current_state_int }
+ \tl_set:Nn \exp_not:N \l_regex_current_submatches_prop
+ { \exp_not:o \l_regex_current_submatches_prop }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_action_submatch:n}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_action_submatch:n #1
+ {
+ \prop_put:Nno \l_regex_current_submatches_prop {#1}
+ { \int_use:N \l_regex_current_step_int }
+ \regex_store_submatches:n { \l_regex_current_state_int }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_action_repeat_copy:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_repeat_move:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_no_repeat_copy:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_no_repeat_move:n { \ERROR }
+% \end{macrocode}
+%
+% \subsection{Submatches, once the correct match is found}
+%
+% \begin{macro}[int]{\regex_extract:}
+% \begin{macro}[aux]{\regex_extract_aux:nTF}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_extract:
+ {
+ \seq_gclear:N \g_regex_submatches_seq
+ \prg_stepwise_inline:nnnn
+ {0} {1} { \l_regex_capturing_group_int }
+ {
+ \regex_extract_aux:nTF { ##1 }
+ {
+ \seq_gput_right:Nx \g_regex_submatches_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \l_regex_tmpa_tl }
+ { \l_regex_tmpb_tl }
+ }
+ }
+ { \seq_gput_right:Nn \g_regex_submatches_seq { } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_extract_aux:nTF #1#2#3
+ {
+ \prop_get:NnNTF \l_regex_success_submatches_prop
+ { #1 < } \l_regex_tmpa_tl
+ {
+ \prop_get:NnNTF \l_regex_success_submatches_prop
+ { #1 > } \l_regex_tmpb_tl
+ {#2}
+ {#3}
+ }
+ {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{User commands}
+%
+% \subsubsection{Precompiled pattern}
+%
+% A given pattern is often reused to match many different strings.
+% We thus give a means of storing the NFA corresponding to a given
+% pattern in a token list variable of the form
+% \begin{quote}
+% \cs{regex_nfa:Nw} \meta{variable~name} \\
+% \meta{assignments} \\
+% \cs{tex_toks:D} 0 \{ \meta{instruction0} \} \\
+% \ldots{} \\
+% \cs{tex_toks:D} $n$ \{ \meta{instruction$\sb{n}$} \} \\
+% \cs{regex_nfa_end:}
+% \end{quote}
+% where $n$ is the number of states in the NFA,
+% and the various \meta{instruction$\sb{i}$} control
+% how the NFA behaves in state $i$. The \cs{regex_nfa:Nw}
+% function removes the whole NFA from the input stream
+% and produces an error: the \meta{nfa var} should only be
+% accessed through dedicated functions. This rather drastic
+% approach is taken because assignments triggered by the
+% contents of \meta{nfa var} may overwrite data which is used
+% elsewhere, unless everything is done carefully in a group.
+%
+% \begin{macro}{\regex_set:Nn}
+% \begin{macro}{\regex_gset:Nn}
+% \begin{macro}[aux]{\regex_set_aux:NNn}
+% \begin{macro}[aux]{\regex_set_aux:n}
+% \begin{macro}[aux]{\regex_nfa:Nw}
+% \begin{macro}[aux]{\regex_nfa_end:}
+% Within a group, build the NFA corresponding to the given regular
+% expression, with submatch tracking. Then save the contents of all
+% relevant \tn{toks} registers into \cs{g_regex_tmpa_tl}, then
+% transferred to the user's tl variable.
+% The auxiliary \cs{regex_nfa:Nw} is not protected: this ensures that
+% the NFA will properly be replaced by an error message in expansion
+% contexts.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_set:Nn
+ { \regex_set_aux:NNn \tl_set_eq:NN }
+\cs_new_protected_nopar:Npn \regex_gset:Nn
+ { \regex_set_aux:NNn \tl_gset_eq:NN }
+\cs_new_protected:Npn \regex_set_aux:NNn #1#2#3
+ {
+ \group_begin:
+ \regex_build:n {#3}
+ \tl_gset:Nx \g_regex_tmpa_tl
+ {
+ \exp_not:N \regex_nfa:Nw \exp_not:N #2
+ \l_regex_max_state_int
+ = \int_use:N \l_regex_max_state_int
+ \l_regex_capturing_group_int
+ = \int_use:N \l_regex_capturing_group_int
+ \bool_if:NTF \l_regex_look_behind_bool
+ { \bool_set_true:N \l_regex_look_behind_bool }
+ { \bool_set_false:N \l_regex_look_behind_bool }
+ \prg_stepwise_function:nnnN
+ {1} {1} {\l_regex_max_state_int}
+ \regex_set_aux:n
+ \regex_nfa_end:
+ }
+ \group_end:
+ #1 #2 \g_regex_tmpa_tl
+ }
+\cs_new_nopar:Npn \regex_set_aux:n #1
+ { \tex_toks:D #1 { \tex_the:D \tex_toks:D #1 } }
+\cs_new:Npn \regex_nfa:Nw #1 #2 \regex_nfa_end:
+ { \msg_expandable_error:n { Automaton~#1 used~incorrectly. } }
+\cs_new_eq:NN \regex_nfa_end: \scan_stop:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int,TF]{\regex_check_nfa:N}
+% If a token list variable starts with \cs{regex_nfa:Nw},
+% then it most likely holds the data for a precompiled pattern.
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \regex_check_nfa:N #1 { TF }
+ { \exp_after:wN \regex_check_nfa_aux:Nw #1 \q_stop }
+\cs_new:Npn \regex_check_nfa_aux:Nw #1 #2 \q_stop
+ {
+ \if_meaning:w \regex_nfa:Nw #1
+ \prg_return_true:
+ \else:
+ \msg_error:nnx { regex } { not-nfa } { \token_to_str:N #1 }
+ \prg_return_false:
+ \fi:
+ }
+\msg_new:nnn { regex } { not-nfa }
+ {
+ I~was~expecting~a~regular~expression~variable.\\
+ Instead,~I~got~#1.
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\regex_use:N}
+% No error-checking.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_use:N #1
+ { \exp_after:wN \use_none:nn #1 }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Generic auxiliary functions}
+%
+% \begin{macro}[aux]{\regex_user_aux:n}
+% This is an auxiliary used by most user functions.
+% The first and second arguments control whether we should track
+% submatches, and whether we track one or multiple submatches.
+% Everything is done within a group, so that |#1| can perform
+% \enquote{unsafe} assignments. Most user functions return a
+% result using \cs{group_insert_after:N}.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_user_aux:n #1
+ {
+ \group_begin:
+ \tl_clear:N \l_regex_every_match_tl
+ #1
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_return_after_group:}
+% Most of \pkg{l3regex}'s work is done within a group.
+% This function triggers either \cs{prg_return_false:}
+% or \cs{prg_return_true:} as appropriate to whether a
+% match was found or not.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_return_after_group:
+ {
+ \if_bool:N \l_regex_success_bool
+ \group_insert_after:N \prg_return_true:
+ \else:
+ \group_insert_after:N \prg_return_false:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_extract_after_group:N}
+% Extract submatches, and store them in the user-given variable
+% after the group has ended.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_extract_after_group:N #1
+ {
+ \if_bool:N \l_regex_success_bool
+ \regex_extract:
+ \group_insert_after:N \seq_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_submatches_seq
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_count_after_group:N}
+% Same procedure as \cs{regex_extract_after_group:N}, but simpler
+% since the match counting has already taken place.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_count_after_group:N #1
+ {
+ \group_insert_after:N \int_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_match_count_int
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Matching}
+%
+% \begin{macro}[TF]{\regex_match:nn}
+% \begin{macro}[TF]{\regex_match:Nn}
+% We don't track submatches. Then either build the NFA corresponding
+% to the regular expression, or use a precompiled pattern. Then match,
+% using the internal \cs{regex_match:n}. Finally return the result
+% after closing the group.
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \regex_match:nn #1#2 { T , F , TF }
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_return_after_group:
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_match:Nn #1#2 { T , F , TF }
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_return_after_group:
+ }
+ }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\regex_count:nnN}
+% \begin{macro}{\regex_count:NnN}
+% Instead of aborting once the first \enquote{best match} is found,
+% we repeat the search. The code is such that the search will not
+% start on the same character, hence avoiding infinite loops.
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_count:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \int_gzero:N \g_regex_match_count_int
+ \tl_set:Nn \l_regex_every_match_tl
+ {
+ \int_gincr:N \g_regex_match_count_int
+ \regex_match_once:
+ }
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_count_after_group:N #3
+ }
+ }
+\cs_new_protected:Npn \regex_count:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \int_gzero:N \g_regex_match_count_int
+ \tl_set:Nn \l_regex_every_match_tl
+ {
+ \int_gincr:N \g_regex_match_count_int
+ \regex_match_once:
+ }
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_count_after_group:N #3
+ }
+ }
+ { }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Submatch extraction}
+%
+% \begin{macro}{\regex_extract:nnN}
+% \begin{macro}{\regex_extract:NnN}
+% \begin{macro}[TF]{\regex_extract:nnN}
+% \begin{macro}[TF]{\regex_extract:NnN}
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_extract:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_extract:nnN #1#2#3 { T , F , TF }
+ {
+ \regex_user_aux:n
+ {
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ \regex_return_after_group:
+ }
+ }
+\cs_new_protected:Npn \regex_extract:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ }
+ }
+ { }
+ }
+\prg_new_protected_conditional:Npnn \regex_extract:NnN #1#2#3 { T , F , TF }
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ \regex_return_after_group:
+ }
+ }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Splitting a string by matches of a regex}
+%
+% \begin{macro}{\regex_split:nnN}
+% \begin{macro}{\regex_split:NnN}
+% \begin{macro}[aux]{\regex_split_aux:}
+% \begin{macro}[aux]{\regex_split_after_group:N}
+% Similarly to \cs{regex_count:nnN} functions,
+% recurse through matches of the pattern. Then we do
+% something slightly different, extracting submatches.
+% Submatches are not extracted if the pattern matched
+% an empty string at the start of the match attempt
+% (to avoid adding spurious empty items to the resulting
+% sequence).
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_split:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \seq_gclear:N \g_regex_split_seq
+ \tl_set:Nn \l_regex_every_match_tl { \regex_split_aux: }
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_split_after_group:N #3
+ }
+ }
+\cs_new_protected:Npn \regex_split:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \seq_gclear:N \g_regex_split_seq
+ \tl_set:Nn \l_regex_every_match_tl { \regex_split_aux: }
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_split_after_group:N #3
+ }
+ }
+ { }
+ }
+\cs_new_protected_nopar:Npn \regex_split_aux:
+ {
+ \int_compare:nNnF \l_regex_start_step_int = \l_regex_success_step_int
+ {
+ \regex_extract:
+ \seq_pop:NN \g_regex_submatches_seq \l_regex_tmpa_tl
+ \regex_extract_aux:nTF {0}
+ {
+ \seq_gput_left:Nx \g_regex_submatches_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \l_regex_tmpa_tl }
+ }
+ }
+ { \msg_error:nn { regex } { internal } }
+ \seq_gconcat:NNN \g_regex_split_seq
+ \g_regex_split_seq \g_regex_submatches_seq
+ }
+ \regex_match_once:
+ }
+\cs_new_protected_nopar:Npn \regex_split_after_group:N #1
+ {
+ \int_compare:nNnTF \l_regex_start_step_int = \l_regex_current_step_int
+ {
+ \bool_if:NF \l_regex_success_empty_bool
+ { \seq_gput_right:Nn \g_regex_split_seq { } }
+ }
+ {
+ \seq_gput_right:Nx \g_regex_split_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \int_use:N \l_regex_current_step_int }
+ }
+ }
+ \group_insert_after:N \seq_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_split_seq
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{String replacement}
+%
+% \begin{macro}[int]{\regex_replacement:n}
+% \begin{macro}[aux]{\regex_replacement_loop:N}
+% \begin{macro}[aux]{\regex_replacement_normal:N}
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_replacement:n #1
+ {
+ \str_aux_escape:NNNn
+ \prg_do_nothing:
+ \regex_replacement_escaped:N
+ \regex_replacement_raw:N
+ {#1}
+ \tl_set_eq:NN \l_regex_replacement_tl \g_str_result_tl
+ \tl_set:Nx \l_regex_replacement_tl
+ { \l_regex_replacement_tl \prg_do_nothing: }
+ }
+\cs_new_nopar:Npn \regex_replacement_raw:N { \exp_not:N \prg_do_nothing: }
+\cs_new_nopar:Npn \regex_replacement_escaped:N #1
+ {
+ \if_num:w 9 < 1 #1 \exp_stop_f:
+ \exp_not:N \regex_replacement_escaped_ii:nN {#1}
+ \else:
+ #1
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_replacement_escaped_ii:nN #1#2
+ {
+ \regex_token_if_other_digit:NTF #2
+ { \regex_replacement_escaped_ii:nN {#1#2} }
+ { \exp_not:N \seq_item:Nn \exp_not:N \g_regex_submatches_seq {#1} #2 }
+ }
+\prg_new_conditional:Npnn \regex_token_if_other_digit:N #1 { TF }
+ {
+ \if_num:w 9 < 1 \exp_not:N #1 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\regex_replace_after_group:N}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \regex_replace_after_group:N #1
+ {
+ \group_insert_after:N \tl_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_replaced_str
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\regex_replace_once:nnN}
+% \begin{macro}{\regex_replace_once:NnN}
+% \begin{macro}[TF]{\regex_replace_once:nnN}
+% \begin{macro}[TF]{\regex_replace_once:NnN}
+% \begin{macro}[aux]{\regex_replace_once_aux:Nn}
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_replace_once_aux:Nn #1#2
+ {
+ \group_begin:
+ \regex_replace_after_group:N #1
+ \tl_clear:N \l_regex_every_match_tl
+ #2
+ \exp_args:No \regex_match:n {#1}
+ \regex_extract:
+ \regex_extract_aux:nTF {0}
+ {
+ \tl_gset:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str {0} { \l_regex_tmpa_tl }
+ \l_regex_replacement_tl
+ \str_from_to:Nnn \l_regex_query_str
+ { \l_regex_tmpb_tl } { \c_max_int }
+ }
+ }
+ { \tl_gset_eq:NN \g_regex_replaced_str \l_regex_query_str }
+ \group_end:
+ }
+\cs_new_protected:Npn \regex_replace_once:nnN #1#2#3
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ }
+ }
+\cs_new_protected:Npn \regex_replace_once:NnN #1#2#3
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_replace_once:nnN #1#2#3 {T,F,TF}
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ \regex_return_after_group:
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_replace_once:NnN #1#2#3 {T,F,TF}
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ \regex_return_after_group:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\regex_replace_all:nnN}
+% \begin{macro}{\regex_replace_all:NnN}
+% \begin{macro}[aux]{\regex_replace_all_aux:Nn}
+% \begin{macro}[aux]{\regex_replace_all_aux:}
+% \begin{macrocode}
+\cs_new_protected:Npn \regex_replace_all_aux:Nn #1#2
+ {
+ \group_begin:
+ \regex_replace_after_group:N #1
+ \tl_set:Nn \l_regex_every_match_tl { \regex_replace_all_aux: }
+ \tl_gclear:N \g_regex_replaced_str
+ #2
+ \exp_args:No \regex_match:n {#1}
+ \tl_gput_right:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \c_max_int }
+ }
+ \group_end:
+ }
+\cs_new_protected_nopar:Npn \regex_replace_all_aux:
+ {
+ \regex_extract:
+ \regex_extract_aux:nTF {0}
+ {
+ \tl_gput_right:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \l_regex_tmpa_tl }
+ \l_regex_replacement_tl
+ }
+ }
+ { \msg_error:nn { regex } { internal } }
+ \regex_match_once:
+ }
+\cs_new_protected:Npn \regex_replace_all:nnN #1#2#3
+ {
+ \regex_replace_all_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ }
+ }
+\cs_new_protected:Npn \regex_replace_all:NnN #1#2#3
+ {
+ \regex_replace_all_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \endinput
+%^^A NOT IMPLEMENTED
+%^^A \cx "control-x", where x is any ASCII character
+%^^A \C one byte, even in UTF-8 mode (best avoided)
+%^^A \p{xx} a character with the xx property
+%^^A \P{xx} a character without the xx property
+%^^A \R a newline sequence
+%^^A \X an extended Unicode sequence
+%^^A [[:xxx:]] positive POSIX named set
+%^^A [[:^xxx:]] negative POSIX named set
+%^^A ?+ 0 or 1, possessive
+%^^A *+ 0 or more, possessive
+%^^A ++ 1 or more, possessive
+%^^A {n,m}+ at least n, no more than m, possessive
+%^^A {n,}+ n or more, possessive
+%^^A \K reset start of match
+%^^A (?<name>...) named capturing group (Perl)
+%^^A (?'name'...) named capturing group (Perl)
+%^^A (?P<name>...) named capturing group (Python)
+%^^A (?:...) non-capturing group
+%^^A (?|...) non-capturing group; reset group numbers for
+%^^A capturing groups in each alternative
+%^^A (?>...) atomic, non-capturing group
+%^^A (?#....) comment (not nestable)
+%^^A (?i) caseless
+%^^A (?J) allow duplicate names
+%^^A (?m) multiline
+%^^A (?s) single line (dotall)
+%^^A (?U) default ungreedy (lazy)
+%^^A (?x) extended (ignore white space)
+%^^A (?-...) unset option(s)
+%^^A (*NO_START_OPT) no start-match optimization (PCRE_NO_START_OPTIMIZE)
+%^^A (*UTF8) set UTF-8 mode (PCRE_UTF8)
+%^^A (*UCP) set PCRE_UCP (use Unicode properties for \d etc)
+%^^A (?=...) positive look ahead
+%^^A (?!...) negative look ahead
+%^^A (?<=...) positive look behind
+%^^A (?<!...) negative look behind
+%^^A \n reference by number (can be ambiguous)
+%^^A \gn reference by number
+%^^A \g{n} reference by number
+%^^A \g{-n} relative reference by number
+%^^A \k<name> reference by name (Perl)
+%^^A \k'name' reference by name (Perl)
+%^^A \g{name} reference by name (Perl)
+%^^A \k{name} reference by name (.NET)
+%^^A (?P=name) reference by name (Python)
+%^^A (?R) recurse whole pattern
+%^^A (?n) call subpattern by absolute number
+%^^A (?+n) call subpattern by relative number
+%^^A (?-n) call subpattern by relative number
+%^^A (?&name) call subpattern by name (Perl)
+%^^A (?P>name) call subpattern by name (Python)
+%^^A \g<name> call subpattern by name (Oniguruma)
+%^^A \g'name' call subpattern by name (Oniguruma)
+%^^A \g<n> call subpattern by absolute number (Oniguruma)
+%^^A \g'n' call subpattern by absolute number (Oniguruma)
+%^^A \g<+n> call subpattern by relative number (PCRE extension)
+%^^A \g'+n' call subpattern by relative number (PCRE extension)
+%^^A \g<-n> call subpattern by relative number (PCRE extension)
+%^^A \g'-n' call subpattern by relative number (PCRE extension)
+%^^A (?(n)... absolute reference condition
+%^^A (?(+n)... relative reference condition
+%^^A (?(-n)... relative reference condition
+%^^A (?(<name>)... named reference condition (Perl)
+%^^A (?('name')... named reference condition (Perl)
+%^^A (?(name)... named reference condition (PCRE)
+%^^A (?(R)... overall recursion condition
+%^^A (?(Rn)... specific group recursion condition
+%^^A (?(R&name)... specific recursion condition
+%^^A (?(DEFINE)... define subpattern for reference
+%^^A (?(assert)... assertion condition
+%^^A (*ACCEPT) force successful match
+%^^A (*FAIL) force backtrack; synonym (*F)
+%^^A (*COMMIT) overall failure, no advance of starting point
+%^^A (*PRUNE) advance to next starting character
+%^^A (*SKIP) advance start to current matching position
+%^^A (*THEN) local failure, backtrack to next alternation
+%^^A (*CR) carriage return only
+%^^A (*LF) linefeed only
+%^^A (*CRLF) carriage return followed by linefeed
+%^^A (*ANYCRLF) all three of the above
+%^^A (*ANY) any Unicode newline sequence
+%^^A (*BSR_ANYCRLF) CR, LF, or CRLF
+%^^A (*BSR_UNICODE) any Unicode newline sequence
+%^^A (?C) callout
+%^^A (?Cn) callout with data n \ No newline at end of file
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx
new file mode 100644
index 00000000000..a718f986ce7
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx
@@ -0,0 +1,1966 @@
+% \iffalse meta-comment
+%
+%% File: l3str.dtx Copyright (C) 2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX3 Project.
+%%
+%% -----------------------------------------------------------------------
+%
+%<*driver|package>
+\RequirePackage{expl3}
+\GetIdInfo$Id: l3str.dtx 2895 2011-10-09 15:58:19Z joseph $
+ {L3 Experimental Strings}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\usepackage{amsmath}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%
+% \title{^^A
+% The \textsf{l3str} package: manipulating strings of characters^^A
+% \thanks{This file describes v\ExplFileVersion,
+% last revised \ExplFileDate.}^^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 \ExplFileDate}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \LaTeX3 provides a set of functions to manipulate token lists
+% as strings of characters, ignoring the category codes of those
+% characters.
+%
+% There is no separate string data type: string variables are simply
+% specialized token lists, conventionally made out only of characters
+% with category code $12$ (other), except spaces, which have category
+% code $10$ (blank space). All the \enquote{safe} functions in this
+% module first convert their argument to a string for internal processing,
+% and will not treat a token list or the corresponding string representation
+% differently. However, it is often better to name token list variables
+% meant to contain string data with a name such as \cs{l_\ldots{}_str}.
+% Those are then manipulated mostly with tools from \pkg{l3tl}.
+%
+% Most functions in this module come in three flavours:
+% \begin{itemize}
+% \item \cs{str_...:N...}, which expect a token list
+% variable as their argument;
+% \item \cs{str_...:n...}, taking any token list (or string) as an argument;
+% \item \cs{str_..._ignore_spaces:n...}, which ignores any space encountered
+% during the operation: these functions are slightly faster than those
+% which take care of escaping spaces appropriately;
+% \end{itemize}
+% When performance is important, the internal \cs{str_..._unsafe:n...}
+% functions, which expect a \enquote{safe} string in which spaces
+% have category code $12$ instead of $10$, might be useful.
+%
+% \subsection{Conversion and input of strings}
+%
+% \begin{variable}{\c_backslash_str,
+% \c_lbrace_str,\c_rbrace_str,\c_hash_str,\c_percent_str}
+% Constant strings, containing a single character, with category code $12$.
+% \end{variable}
+%
+% \begin{function}[EXP]{\tl_to_str:N,\tl_to_str:n}
+% \begin{syntax}
+% \cs{tl_to_str:N} \meta{tl var}
+% \cs{tl_to_str:n} \Arg{token list}
+% \end{syntax}
+% Converts the \meta{token list} to a \meta{string}.
+% \end{function}
+%
+% \begin{function}
+% {
+% \str_set:Nn, \str_set:Nx,
+% \str_set:cn, \str_set:cx,
+% \str_gset:Nn, \str_gset:Nx,
+% \str_gset:cn, \str_gset:cx,
+% }
+% \begin{function}
+% {
+% \str_put_left:Nn, \str_put_left:Nx,
+% \str_put_left:cn, \str_put_left:cx,
+% \str_gput_left:Nn, \str_gput_left:Nx,
+% \str_gput_left:cn, \str_gput_left:cx,
+% }
+% \begin{function}
+% {
+% \str_put_right:Nn, \str_put_right:Nx,
+% \str_put_right:cn, \str_put_right:cx,
+% \str_gput_right:Nn, \str_gput_right:Nx,
+% \str_gput_right:cn, \str_gput_right:cx,
+% }
+% \begin{syntax}
+% \cs{str_set:Nn} \meta{str var} \Arg{token list}
+% \end{syntax}
+% Converts the \meta{token list} to a \meta{string},
+% and saves the result in \meta{str var}.
+% \end{function}
+% \end{function}
+% \end{function}
+%
+% \begin{function}{\str_input:Nn,\str_ginput:Nn}
+% \begin{syntax}
+% \cs{str_input:Nn} \meta{str var} \Arg{token list}
+% \end{syntax}
+% Converts the \meta{token list} into a \meta{string}, and stores
+% it in the \meta{str var}. Special characters can be input by
+% escaping them with a backslash.
+% \begin{itemize}
+% \item Spaces are ignored unless escaped with a backslash.
+% \item |\xhh| produces the character with code \texttt{hh}
+% in hexadecimal: when |\x| is encountered, up to two hexadecimal digits
+% (\texttt{0}--\texttt{9}, \texttt{a}--\texttt{f}, \texttt{A}--\texttt{F})
+% are read to give a number between $0$ and $255$.
+% \item |\x{hh...}| produces the character with code \texttt{hh...}
+% (an aribtrary number of hexadecimal digits are read):
+% this is mostly useful for Lua\TeX{} and Xe\TeX{}.
+% \item |\a|, |\e|, |\f|, |\n|, |\r|, |\t| stand for specific characters:
+% \begin{center}
+% \begin{tabular}{cccc}
+% |\a| & |\^^G| & alarm & hex \texttt{07} \\
+% |\e| & |\^^[| & escape & hex \texttt{1B} \\
+% |\f| & |\^^L| & form feed & hex \texttt{0C} \\
+% |\n| & |\^^J| & new line & hex \texttt{0A} \\
+% |\r| & |\^^M| & carriage return & hex \texttt{0D} \\
+% |\t| & |\^^I| & horizontal tab & hex \texttt{09} \\
+% \end{tabular}
+% \end{center}
+% \end{itemize}
+% For instance,
+% \begin{quote}
+% \cs{tl_new:N} \cs{l_my_str} \\
+% \cs{str_input:Nn} \cs{l_my_str} |{\x3C \\ \# abc\ def\^}|
+% \end{quote}
+% results in \cs{l_my_str} containing the characters |\<#abc def^|,
+% since |<| has ascii code \texttt{3C} (in hexadecimal).
+% \end{function}
+%
+% \subsection{Characters given by their position}
+%
+% \begin{function}[EXP]{\str_length:N}
+% \begin{function}[EXP]{\str_length:n}
+% \begin{function}[EXP]{\str_length_ignore_spaces:n}
+% \begin{syntax}
+% \cs{str_length:n} \Arg{token list}
+% \end{syntax}
+% Leaves the length of the string representation of \meta{token list}
+% in the input stream. The functions differ in their treatment of spaces.
+% In the case of \cs{str_length:N} and \cs{str_length:n},
+% all characters including spaces are counted.
+% The \cs{str_length_ignore_spaces:n} returns the number of non-space
+% characters.
+% \begin{texnote}
+% The \cs{str_length:n} of a given token list may depend
+% on the category codes in effect when it is measured,
+% and the value of the \tn{escapechar}: for instance
+% |\str_length:n {\a}| may return $1$, $2$ or $3$ depending
+% on the escape character, and the category code of \texttt{a}.
+% \end{texnote}
+% \end{function}
+% \end{function}
+% \end{function}
+%
+% \begin{function}[EXP]{\str_head:N}
+% \begin{function}[EXP]{\str_head:n}
+% \begin{function}[EXP]{\str_head_ignore_spaces:n}
+% \begin{syntax}
+% \cs{str_head:n} \Arg{token list}
+% \end{syntax}
+% Converts the \meta{token list} into a \meta{string}.
+% The first character in the \meta{string} is then
+% left in the input stream, with category code \enquote{other}.
+% The functions differ in their treatment of spaces.
+% In the case of \cs{str_head:N} and \cs{str_head:n},
+% a leading space is returned with category code $10$ (blank space).
+% The \cs{str_head_ignore_spaces:n} function returns the first
+% non-space character.
+% If the \meta{token list} is empty (or blank in the case of the
+% \texttt{_ignore_spaces} variant), then nothing is left on the
+% input stream.
+% \end{function}
+% \end{function}
+% \end{function}
+%
+% \begin{function}[EXP]{\str_tail:N}
+% \begin{function}[EXP]{\str_tail:n}
+% \begin{function}[EXP]{\str_tail_ignore_spaces:n}
+% \begin{syntax}
+% \cs{str_tail:n} \Arg{token list}
+% \end{syntax}
+% Converts the \meta{token list} to a \meta{string},
+% removes the first character, and leaves
+% the remaining characters (if any) in the input stream,
+% with category codes $12$ and $10$ (for spaces).
+% The functions differ in the case where the first character
+% is a space: \cs{str_tail:N} and \cs{str_tail:n} will trim
+% only that space, while \cs{str_tail_ignore_spaces:n} trims
+% the first non-space character.
+% \end{function}
+% \end{function}
+% \end{function}
+%
+% \begin{function}[EXP]{\str_item:Nn}
+% \begin{function}[EXP]{\str_item:nn}
+% \begin{function}[EXP]{\str_item_ignore_spaces:nn}
+% \begin{syntax}
+% \cs{str_item:nn} \Arg{token list} \Arg{integer expression}
+% \end{syntax}
+% Converts the \meta{token list} to a \meta{string}, and
+% leaves in the input stream the character in position
+% \meta{integer expression} of the \meta{string}.
+% In the case of \cs{str_item:Nn} and \cs{str_item:nn},
+% all characters including spaces are taken into account.
+% The \cs{str_item_ignore_spaces:nn} function skips spaces
+% in its argument.
+% If the \meta{integer expression} is negative, characters
+% are counted from the end of the \meta{string}. Hence, $-1$ is
+% the right-most character, \emph{etc.}, while $0$ is the first
+% (left-most) character.
+% \end{function}
+% \end{function}
+% \end{function}
+%
+% \begin{function}[EXP]{\str_from_to:Nnn}
+% \begin{function}[EXP]{\str_from_to:nnn}
+% \begin{function}[EXP]{\str_from_to_ignore_spaces:nnn}
+% \begin{syntax}
+% \cs{str_from_to:nnn} \Arg{token list} \Arg{start index} \Arg{end index}
+% \end{syntax}
+% Converts the \meta{token list} to a \meta{string},
+% and leaves in the input stream the characters
+% between \meta{start index} (inclusive) and \meta{end index} (exclusive).
+% If either of \meta{start index} or \meta{end index} is negative,
+% the it is incremented by the length of the list.
+% \end{function}
+% \end{function}
+% \end{function}
+%
+% \subsection{String conditionals}
+%
+% \begin{function}[EXP,pTF]{\str_if_eq:NN}
+% \begin{function}[EXP,pTF]
+% {
+% \str_if_eq:nn, \str_if_eq:Vn, \str_if_eq:on, \str_if_eq:no,
+% \str_if_eq:nV, \str_if_eq:VV, \str_if_eq:xx
+% }
+% \begin{syntax}
+% \cs{str_if_eq_p:nn} \Arg{tl1} \Arg{tl2}
+% \cs{str_if_eq:nnTF} \Arg{tl1} \Arg{tl2} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Compares the two \meta{token lists} on a character by character
+% basis, and is \texttt{true} if the two lists contain the same
+% characters in the same order. Thus for example
+% \begin{verbatim}
+% \str_if_eq_p:xx { abc } { \tl_to_str:n { abc } }
+% \end{verbatim}
+% is logically \texttt{true}. All versions of these functions are fully
+% expandable (including those involving an \texttt{x}-type
+% expansion).
+% \end{function}
+% \end{function}
+%
+% \begin{function}[EXP,pTF]{\str_if_contains_char:NN}
+% \begin{function}[EXP,pTF]{\str_if_contains_char:nN}
+% \begin{syntax}
+% \cs{str_if_contains_char:nN} \Arg{token list} \meta{char}
+% \end{syntax}
+% Converts the \meta{token list} to a \meta{string}
+% and tests whether the \meta{char} is present in the \meta{string}.
+% The \meta{char} can be given either directly, or as a one
+% letter control sequence.
+% \end{function}
+% \end{function}
+%
+% \subsection{Bytes and encoding}
+%
+% \subsubsection{Conditionals}
+%
+% \begin{function}[EXP,pTF]{\str_if_bytes:N}
+% \begin{syntax}
+% \cs{str_if_bytes:NTF} \meta{str var} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests whether the \meta{str var} only contains characters
+% in the range $0$--$255$.
+% \end{function}
+%
+% \begin{function}[EXP,pTF]{\str_if_UTF_viii:N}
+% \begin{syntax}
+% \cs{str_if_UTF_viii:N} \meta{str var} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests whether the \meta{str var} only contains characters
+% in the range $0$--$255$, and forms a valid \texttt{UTF8} string.
+% \textbf{Missing!} ^^A Missing.
+% \end{function}
+%
+% \subsubsection{Conversion}
+%
+% \begin{function}{\str_native_from_UTF_viii:NN}
+% \begin{syntax}
+% \cs{str_native_from_UTF_viii:NN} \meta{str~var1} \meta{str~var2}
+% \end{syntax}
+% Reads the contents of the \meta{str~var2} as an \texttt{UTF8}-encoded
+% sequence of bytes, and stores the resulting characters (which can
+% now have any character code) into \meta{str~var1}.
+% This function raises an error if the \meta{str~var2} is not
+% a valid sequence of bytes in the \texttt{UTF8} encoding.
+% In the \pdfTeX{} engine, this function raises an error if any of the
+% resulting characters is outside the range $0$--$255$ (in other words,
+% don't use this function with \pdfTeX{}).
+% \end{function}
+%
+% \begin{function}{\str_UTF_viii_from_native:NN}
+% \begin{syntax}
+% \cs{str_UTF_viii_from_native:NN} \meta{str~var1} \meta{str~var2}
+% \end{syntax}
+% Converts each character of the \meta{str~var2} into
+% a sequence of bytes, as defined by the \texttt{UTF8}
+% encoding, and stores the result in \meta{str~var1}.
+% In the \pdfTeX{} engine, this function is of course
+% of very little use, but can be used without harm:
+% characters in the range $0$--$127$ are left unchanged,
+% and characters in the range $128$--$255$ become two-byte
+% sequences, as per the definition of \texttt{UTF8}.
+% \end{function}
+%
+% \begin{function}{\str_bytes_escape_hexadecimal:NN}
+% \begin{function}{\str_bytes_unescape_hexadecimal:NN}
+% \begin{syntax}
+% \cs{str_bytes_escape_hexadecimal:NN} \meta{str var1} \meta{str var2}
+% \cs{str_bytes_unescape_hexadecimal:NN} \meta{str var1} \meta{str var2}
+% \end{syntax}
+% See \tn{pdfescapehex}. ^^A missing doc
+% \end{function}
+% \end{function}
+%
+% \begin{function}{\str_bytes_escape_name:NN}
+% \begin{function}{\str_bytes_unescape_name:NN}
+% \begin{syntax}
+% \cs{str_bytes_escape_name:NN} \meta{str var1} \meta{str var2}
+% \cs{str_bytes_unescape_name:NN} \meta{str var1} \meta{str var2}
+% \end{syntax}
+% See \tn{pdfescapename}. ^^A missing doc
+% \end{function}
+% \end{function}
+%
+% \begin{function}{\str_bytes_escape_string:NN}
+% \begin{function}{\str_bytes_unescape_string:NN}
+% \begin{syntax}
+% \cs{str_bytes_escape_string:NN} \meta{str var1} \meta{str var2}
+% \cs{str_bytes_unescape_string:NN} \meta{str var1} \meta{str var2}
+% \end{syntax}
+% See \tn{pdfescapestring}. ^^A missing doc
+% \end{function}
+% \end{function}
+%
+% \begin{function}{\str_bytes_percent_encode:NN}
+% \begin{function}{\str_bytes_percent_decode:NN}
+% \begin{syntax}
+% \cs{str_bytes_percent_encode:NN} meta{str var1} \meta{str var2}
+% \cs{str_bytes_percent_decode:NN} meta{str var1} \meta{str var2}
+% \end{syntax}
+% Used for urls. ^^A missing doc
+% \end{function}
+% \end{function}
+%
+% \subsection{Internal string functions}
+%
+% \begin{function}[EXP]{\tl_to_other_str:N,\tl_to_other_str:n}
+% \begin{syntax}
+% \cs{tl_to_other_str:n} \Arg{token list}
+% \end{syntax}
+% Converts the \meta{token list} to an \meta{other string}, where
+% spaces have category code \enquote{other}. These functions create
+% \enquote{safe} strings.
+% \begin{texnote}
+% These functions can be \texttt{f}-expanded without fear of losing
+% a leading space, since spaces do not have category code $10$ in
+% their result.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}[EXP]{\str_sanitize_args:Nn,\str_sanitize_args:Nnn}
+% \begin{syntax}
+% \cs{str_sanitize_args:Nnn} \meta{function}
+% ~~\Arg{token list1} \Arg{token list2}
+% \end{syntax}
+% Converts the \meta{token lists} to \enquote{safe} strings
+% (where spaces have category code \enquote{other}),
+% and hands-in the result as arguments to \meta{function}.
+% \end{function}
+%
+% \begin{function}[rEXP]{\str_map_tokens:Nn}
+% \begin{syntax}
+% \cs{str_map_tokens:Nn} \meta{str var} \meta{tokens}
+% \end{syntax}
+% Maps the \meta{tokens} over every character in the \meta{str var}.
+% \end{function}
+%
+% \begin{function}{\str_aux_escape:NNNn}
+% \begin{syntax}
+% \cs{str_aux_escape:NNNn} \meta{fn1} \meta{fn2} \meta{fn3} \Arg{token list}
+% \end{syntax}
+% The \meta{token list} is converted to a string, then read from
+% left to right, interpreting backslashes as escaping the next character.
+% Unescaped characters are fed to the function \meta{fn1},
+% and escaped characters are fed to the function \meta{fn2}
+% within an \texttt{x}-expansion context (typically those functions
+% perform some tests on their argument to decide how to output them).
+% The escape sequences |\a|, |\e|, |\f|, |\n|, |\r|, |\t| and |\x|
+% are recognized as described for \cs{str_input:Nn}, and those
+% are replaced by the corresponding character, then fed to
+% \meta{fn3}. The result is assigned globally to \cs{g_str_result_tl}.
+% \end{function}
+%
+% \subsection{Possibilities}
+%
+% \begin{itemize}
+% \item More encodings (see Heiko's \pkg{stringenc}).
+% In particular, what is needed for pdf: \texttt{UTF-16}?
+% \item \cs{str_between:nnn} \Arg{str}
+% \Arg{begin delimiter} \Arg{end delimiter} giving the piece of
+% \meta{str} between \meta{begin} and \meta{end}; could be used
+% with empty \meta{begin} or \meta{end} to indicate that we
+% want everything until \meta{end} or starting from \meta{begin},
+% respectively;
+% \item \cs{str_count_in:nn} \Arg{str} \Arg{substr} giving the number
+% of occurrences of \meta{substr} in \meta{str};
+% \item \cs{str_if_head_eq:nN} alias of \cs{tl_if_head_eq_charcode:nN}
+% \item \cs{str_if_numeric/decimal/integer:n}, perhaps in \pkg{l3fp}?
+% \end{itemize}
+% Some functionalities of \pkg{stringstrings} and \pkg{xstring} as well.
+%
+%^^A Should "str_item" be "str_char"?
+%^^A Should "str_from_to" be "str_substr"?
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3str} implementation}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+% \end{macrocode}
+%
+% Those string-related functions are defined in \pkg{l3kernel}.
+% \begin{itemize}
+% \item \cs{str_if_eq:nn}[pTF] and variants,
+% \item \cs{str_if_eq_return:on},
+% \item \cs{tl_to_str:n}, \cs{tl_to_str:N}, \cs{tl_to_str:c},
+% \item \cs{token_to_str:N}, \cs{cs_to_str:N}
+% \item \cs{str_head:n}, \cs{str_head_aux:w}, (changed behaviour slightly)
+% \item \cs{str_tail:n}, \cs{str_tail_aux:w}, (changed behaviour slightly)
+% \item \cs{str_length_skip_spaces} (deprecated)
+% \item \cs{str_length_loop:NNNNNNNNN} (unchanged)
+% \end{itemize}
+%
+% \subsection{General functions}
+%
+% \begin{macro}[EXP,aux]{\cs_if_exist_use:cF}
+% This function could be moved to a different module in \pkg{l3kernel}.
+% If the control sequence exists, use it,
+% otherwise fall back to a default behaviour.
+% \begin{macrocode}
+\cs_if_exist:NF \cs_if_exist_use:cF
+ {
+ \cs_new:Npn \cs_if_exist_use:cF #1
+ { \cs_if_exist:cTF {#1} { \use:c {#1} } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP,aux]{\use_i:nnnnnnnn}
+% A function which may already be defined elsewhere.
+% \begin{macrocode}
+\cs_if_exist:NF \use_i:nnnnnnnn
+ { \cs_new:Npn \use_i:nnnnnnnn #1#2#3#4#5#6#7#8 {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \str_set:Nn, \str_set:Nx,
+% \str_set:cn, \str_set:cx,
+% \str_gset:Nn, \str_gset:Nx,
+% \str_gset:cn, \str_gset:cx,
+% \str_put_left:Nn, \str_put_left:Nx,
+% \str_put_left:cn, \str_put_left:cx,
+% \str_gput_left:Nn, \str_gput_left:Nx,
+% \str_gput_left:cn, \str_gput_left:cx,
+% \str_put_right:Nn, \str_put_right:Nx,
+% \str_put_right:cn, \str_put_right:cx,
+% \str_gput_right:Nn, \str_gput_right:Nx,
+% \str_gput_right:cn, \str_gput_right:cx,
+% }
+% Simply convert the token list inputs to \meta{strings}.
+% \begin{macrocode}
+\cs_set:Npn \str_tmp:w #1
+ {
+ \cs_new_protected:cpx { str_#1:Nn } ##1##2
+ { \exp_not:c { tl_#1:Nx } ##1 { \exp_not:N \tl_to_str:n {##2} } }
+ \exp_args:Nc \cs_generate_variant:Nn { str_#1:Nn } { Nx , cn , cx }
+ }
+\str_tmp:w {set}
+\str_tmp:w {gset}
+\str_tmp:w {put_left}
+\str_tmp:w {gput_left}
+\str_tmp:w {put_right}
+\str_tmp:w {gput_right}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Variables and constants}
+%
+% \begin{macro}{\str_tmp:w}
+% \begin{variable}{\g_str_tmpa_tl}
+% Internal scratch space for some functions.
+% \begin{macrocode}
+\cs_set_protected_nopar:Npn \str_tmp:w { }
+\tl_new:N \g_str_tmpa_tl
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{variable}{\g_str_result_tl}
+% The \cs{g_str_result_tl} variable is used to hold the result
+% of various internal string operations 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_str_result_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_str_char_int,\l_str_bytes_int}
+% When converting from various escaped forms to raw characters,
+% we often need to read several digits (hexadecimal or octal depending
+% on the case) and keep track of the corresponding character code
+% in \cs{l_str_char_int}. For UTF-8 support, the number of bytes
+% of for the current character is stored in \cs{l_str_bytes_int}.
+% \begin{macrocode}
+\int_new:N \l_str_char_int
+\int_new:N \l_str_bytes_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_backslash_str,
+% \c_lbrace_str,\c_rbrace_str,\c_hash_str,\c_percent_str}
+% For all of those strings, \cs{cs_to_str:N} produce characters
+% with the correct category code.
+% \begin{macrocode}
+\tl_const:Nx \c_backslash_str { \cs_to_str:N \\ }
+\tl_const:Nx \c_lbrace_str { \cs_to_str:N \{ }
+\tl_const:Nx \c_rbrace_str { \cs_to_str:N \} }
+\tl_const:Nx \c_hash_str { \cs_to_str:N \# }
+\tl_const:Nx \c_percent_str { \cs_to_str:N \% }
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Escaping spaces}
+%
+% \begin{macro}[EXP]{\tl_to_other_str:N,\tl_to_other_str:n}
+% \begin{macro}[EXP,aux]{\tl_to_other_str_loop:w,\tl_to_other_str_end:w}
+% Replaces all spaces by \enquote{other} spaces, after converting
+% the token list to a string via \cs{tl_to_str:n}.
+% \begin{macrocode}
+\group_begin:
+\char_set_lccode:nn {`\*}{`\ }
+\char_set_lccode:nn {`\A}{`\A}
+\tl_to_lowercase:n {
+ \group_end:
+ \cs_new:Npn \tl_to_other_str:n #1
+ {
+ \exp_after:wN \tl_to_other_str_loop:w \tl_to_str:n {#1} ~ %
+ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_mark \q_stop
+ }
+ \cs_new_nopar:Npn \tl_to_other_str_loop:w
+ #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 \q_stop
+ {
+ \if_meaning:w A #8
+ \tl_to_other_str_end:w
+ \fi:
+ \tl_to_other_str_loop:w
+ #9 #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * \q_stop
+ }
+ \cs_new_nopar:Npn \tl_to_other_str_end:w \fi: #1 \q_mark #2 * A #3 \q_stop
+ { \fi: #2 }
+}
+\cs_new_nopar:Npn \tl_to_other_str:N
+ { \exp_args:No \tl_to_other_str:n }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\str_sanitize_args:Nn,\str_sanitize_args:Nnn}
+% Here, \texttt{f}-expansion does not lose leading spaces,
+% since they have catcode \enquote{other} after \cs{str_sanitize:n}.
+% \begin{macrocode}
+\cs_new:Npn \str_sanitize_args:Nn #1 #2
+ {
+ \exp_args:Nf #1
+ { \tl_to_other_str:n {#2} }
+ }
+\cs_new:Npn \str_sanitize_args:Nnn #1#2#3
+ {
+ \exp_args:Nff #1
+ { \tl_to_other_str:n {#2} }
+ { \tl_to_other_str:n {#3} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Characters given by their position}
+%
+% \begin{macro}[EXP]{\str_length:N}
+% \begin{macro}[EXP]{\str_length:n}
+% \begin{macro}[EXP]{\str_length_ignore_spaces:n}
+% \begin{macro}[EXP]{\str_length_unsafe:n}
+% \begin{macro}[EXP,aux]{\str_length_aux:n,\str_length_loop:NNNNNNNNN}
+% The length of a string is found by first changing all spaces
+% to other spaces using \cs{tl_to_other_str:n}, then counting
+% characters $9$ at a time. When the end is reached, |#9|
+% has the form |X|\meta{digit}, the catcode test is true,
+% the digit gets added to the sum, and the loop is terminated
+% by \cs{use_none_delimit_by_q_stop:w}.
+% \begin{macrocode}
+\cs_new_nopar:Npn \str_length:N { \exp_args:No \str_length:n }
+\cs_new:Npn \str_length:n { \str_sanitize_args:Nn \str_length_unsafe:n }
+\cs_new_nopar:Npn \str_length_unsafe:n #1
+ { \str_length_aux:n { \str_length_loop:NNNNNNNNN #1 } }
+\cs_new:Npn \str_length_ignore_spaces:n #1
+ {
+ \str_length_aux:n
+ { \exp_after:wN \str_length_loop:NNNNNNNNN \tl_to_str:n {#1} }
+ }
+\cs_new:Npn \str_length_aux:n #1
+ {
+ \int_eval:n
+ {
+ #1
+ { X \c_eight } { X \c_seven } { X \c_six }
+ { X \c_five } { X \c_four } { X \c_three }
+ { X \c_two } { X \c_one } { X \c_zero }
+ \q_stop
+ }
+ }
+\cs_set:Npn \str_length_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9
+ {
+ \if_catcode:w X #9
+ \exp_after:wN \use_none_delimit_by_q_stop:w
+ \fi:
+ \c_nine + \str_length_loop:NNNNNNNNN
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\str_head:N}
+% \begin{macro}[EXP]{\str_head:n}
+% \begin{macro}[EXP]{\str_head_ignore_spaces:n}
+% \begin{macro}[EXP]{\str_head_unsafe:n}
+% \begin{macro}[EXP,aux]{\str_head_aux:w}
+% The cases of \cs{str_head_ignore_spaces:n} and
+% \cs{str_head_unsafe:n} are mostly identical to
+% \cs{tl_head:n}.
+% As usual, \cs{str_head:N} expands its argument and hands it to
+% \cs{str_head:n}. To circumvent the fact that \TeX{} skips spaces
+% when grabbing undelimited macro parameters, \cs{str_head_aux:w}
+% takes an argument delimited by a space. If |#1| starts with a
+% non-space character, \cs{use_i_delimit_by_q_stop:nw} leaves that
+% in the input stream. On the other hand, if |#1| starts with a
+% space, the \cs{str_head_aux:w} takes an empty argument, and
+% the single (braced) space in the definition of \cs{str_head_aux:w}
+% makes its way to the output. Finally, for an empty argument,
+% the (braced) empty brace group in the definition of \cs{str_head:n}
+% gives an empty result after passing through
+% \cs{use_i_delimit_by_q_stop:nw}.
+% \begin{macrocode}
+\cs_set_nopar:Npn \str_head:N { \exp_args:No \str_head:n }
+\cs_set:Npn \str_head:n #1
+ {
+ \exp_after:wN \str_head_aux:w
+ \tl_to_str:n {#1}
+ { { } } ~ \q_stop
+ }
+\cs_set_nopar:Npx \str_head_aux:w #1 ~ %
+ { \exp_not:N \use_i_delimit_by_q_stop:nw #1 { ~ } }
+\cs_new:Npn \str_head_ignore_spaces:n #1
+ { \exp_after:wN \use_i_delimit_by_q_stop:nw \tl_to_str:n {#1} { } \q_stop }
+\cs_new_nopar:Npn \str_head_unsafe:n #1
+ { \use_i_delimit_by_q_stop:nw #1 { } \q_stop }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\str_tail:N}
+% \begin{macro}[EXP]{\str_tail:n}
+% \begin{macro}[EXP]{\str_tail_ignore_spaces:n}
+% \begin{macro}[EXP]{\str_tail_unsafe:n}
+% \begin{macro}[EXP,aux]{\str_tail_aux:w}
+% \begin{macro}[EXP,aux]{\str_tail_aux_ii:w}
+% As when fetching the head of a string, the cases
+% \enquote{\texttt{ignore_spaces:n}} and \enquote{\texttt{unsafe:n}}
+% are similar to \cs{tl_tail:n}.
+% The more commonly used \cs{str_tail:n} function is a little bit
+% more convoluted: hitting the front of the string with
+% \cs{reverse_if:N} \cs{if_charcode:w} \cs{scan_stop:}
+% removes the first character (which necessarily makes the test true,
+% since it cannot match \cs{scan_stop:}). The auxiliary function inserts
+% the required \cs{fi:} to close the conditional, and leaves the tail
+% of the string in the input string. The details are such that an empty
+% string has an empty tail.
+% \begin{macrocode}
+\cs_new_nopar:Npn \str_tail:N { \exp_args:No \str_tail:n }
+\cs_set:Npn \str_tail:n #1
+ {
+ \exp_after:wN \str_tail_aux:w
+ \reverse_if:N \if_charcode:w
+ \scan_stop: \tl_to_str:n {#1} X X \q_stop
+ }
+\cs_set_nopar:Npn \str_tail_aux:w #1 X #2 \q_stop { \fi: #1 }
+\cs_new:Npn \str_tail_ignore_spaces:n #1
+ {
+ \exp_after:wN \str_tail_aux_ii:w
+ \tl_to_str:n {#1} X { } X \q_stop
+ }
+\cs_new_nopar:Npn \str_tail_unsafe:n #1
+ { \str_tail_aux_ii:w #1 X { } X \q_stop }
+\cs_set_nopar:Npn \str_tail_aux_ii:w #1 #2 X #3 \q_stop { #2 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP,int]{\str_skip_do:nn}
+% \begin{macro}[EXP,aux]{\str_skip_aux:nnnnnnnnn}
+% \begin{macro}[EXP,aux]{\str_skip_end:nn}
+% \begin{macro}[EXP,aux]{\str_skip_end_ii:nwn}
+% Removes |max(#1,0)| characters then leaves |#2| in the input stream.
+% We remove characters $7$ at a time. When the number of characters
+% to remove is not a multiple of $7$, we need to remove less than
+% $7$ characters in the last step. This is done by inserting a number
+% of \texttt{X}, which are discarded as if they were part of the string.
+% \begin{macrocode}
+\cs_new:Npn \str_skip_do:nn #1
+ {
+ \int_compare:nNnTF {#1} > \c_seven
+ { \str_skip_aux:nnnnnnnnn }
+ { \str_skip_end:n }
+ {#1}
+ }
+\cs_new:Npn \str_skip_aux:nnnnnnnnn #1#2 #3#4#5#6#7#8#9
+ { \exp_args:Nf \str_skip_do:nn { \int_eval:n { #1 - \c_seven } } {#2} }
+\cs_new:Npn \str_skip_end:n #1
+ {
+ \if_case:w \int_eval:w #1 \int_eval_end:
+ \str_skip_end_ii:nwn { XXXXXXX }
+ \or: \str_skip_end_ii:nwn { XXXXXX }
+ \or: \str_skip_end_ii:nwn { XXXXX }
+ \or: \str_skip_end_ii:nwn { XXXX }
+ \or: \str_skip_end_ii:nwn { XXX }
+ \or: \str_skip_end_ii:nwn { XX }
+ \or: \str_skip_end_ii:nwn { X }
+ \or: \str_skip_end_ii:nwn { }
+ \else: \str_skip_end_ii:nwn { XXXXXXX }
+ \fi:
+ }
+\cs_new:Npn \str_skip_end_ii:nwn #1 #2 \fi: #3
+ { \fi: \use_i:nnnnnnnn {#3} #1 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP,int]{\str_collect_do:nn}
+% \begin{macro}[EXP,aux]{\str_collect_aux:n,\str_collect_aux:nnNNNNNNN}
+% \begin{macro}[EXP,aux]
+% {
+% \str_collect_end:nn,
+% \str_collect_end_ii:nwn,
+% \str_collect_end_iii:nwNNNNNNN
+% }
+% Collects |max(#1,0)| characters, and feeds them as an argument to |#2|.
+% Again, we grab $7$ characters at a time. Instead of inserting
+% a string of \texttt{X} to fill in to a multiple of $7$, we insert
+% empty groups, so that they disappear in this context where arguments
+% are accumulated.
+% \begin{macrocode}
+\cs_new:Npn \str_collect_do:nn #1#2
+ { \str_collect_aux:n {#1} { \str_collect_end_iii:nwNNNNNNN {#2} } }
+\cs_new:Npn \str_collect_aux:n #1
+ {
+ \int_compare:nNnTF {#1} > \c_seven
+ { \str_collect_aux:nnNNNNNNN }
+ { \str_collect_end:n }
+ {#1}
+ }
+\cs_new:Npn \str_collect_aux:nnNNNNNNN #1#2 #3#4#5#6#7#8#9
+ {
+ \exp_args:Nf \str_collect_aux:n
+ { \int_eval:n { #1 - \c_seven } }
+ { #2 #3#4#5#6#7#8#9 }
+ }
+\cs_new:Npn \str_collect_end:n #1
+ {
+ \if_case:w \int_eval:w #1 \int_eval_end:
+ \str_collect_end_ii:nwn { {}{}{}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{} }
+ \or: \str_collect_end_ii:nwn { {} }
+ \or: \str_collect_end_ii:nwn { }
+ \else: \str_collect_end_ii:nwn { {}{}{}{}{}{}{} }
+ \fi:
+ }
+\cs_new:Npn \str_collect_end_ii:nwn #1 #2 \fi: #3
+ { \fi: #3 \q_stop #1 }
+\cs_new:Npn \str_collect_end_iii:nwNNNNNNN #1 #2 \q_stop #3#4#5#6#7#8#9
+ { #1 {#2#3#4#5#6#7#8#9} }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\str_item:Nn}
+% \begin{macro}[EXP]{\str_item:nn}
+% \begin{macro}[EXP]{\str_item_ignore_spaces:nn}
+% \begin{macro}[EXP]{\str_item_unsafe:nn}
+% \begin{macro}[EXP,aux]{\str_item_aux:nn}
+% This is mostly shuffling arguments around to avoid measuring
+% the length of the string more than once, and make sure that
+% the parameters given to \cs{str_skip_do:nn} are necessarily
+% within the bounds of the length of the string.
+% The \cs{str_item_ignore_spaces:nn} function cheats a little bit
+% in that it doesn't hand to \cs{str_item_unsafe:nn} a truly
+% \enquote{safe} string. This is alright, as everything else
+% is done with undelimited arguments.
+% \begin{macrocode}
+\cs_new_nopar:Npn \str_item:Nn { \exp_args:No \str_item:nn }
+\cs_new:Npn \str_item:nn #1#2
+ {
+ \exp_args:Nf \tl_to_str:n
+ { \str_sanitize_args:Nn \str_item_unsafe:nn {#1} {#2} }
+ }
+\cs_new:Npn \str_item_ignore_spaces:nn #1
+ { \exp_args:No \str_item_unsafe:nn { \tl_to_str:n {#1} } }
+\cs_new_nopar:Npn \str_item_unsafe:nn #1#2
+ {
+ \exp_args:Nff \str_item_aux:nn
+ { \int_eval:n {#2} }
+ { \str_length_unsafe:n {#1} }
+ #1
+ \q_stop
+ }
+\cs_new_nopar:Npn \str_item_aux:nn #1#2
+ {
+ \int_compare:nNnTF {#1} < \c_zero
+ {
+ \int_compare:nNnTF {#1} < {-#2}
+ { \use_none_delimit_by_q_stop:w }
+ {
+ \str_skip_do:nn { #1 + #2 }
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ }
+ {
+ \int_compare:nNnTF {#1} < {#2}
+ {
+ \str_skip_do:nn {#1}
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ { \use_none_delimit_by_q_stop:w }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\str_from_to:Nnn}
+% \begin{macro}[EXP]{\str_from_to:nnn}
+% \begin{macro}[EXP]{\str_from_to_ignore_spaces:nnn}
+% \begin{macro}[EXP]{\str_from_to_unsafe:nnn}
+% \begin{macro}[EXP,aux]{\str_from_to_aux:nnnw}
+% \begin{macro}[EXP,aux]{\str_from_to_aux_ii:nnw}
+% \begin{macro}[EXP,aux]{\str_aux_eval_args:Nnnn}
+% \begin{macro}[EXP,aux]{\str_aux_normalize_range:nn}
+% Sanitize the string, then limit the second and third arguments
+% to be at most the length of the string (this avoids needing
+% to check for the end of the string when grabbing characters).
+% Afterwards, skip characters, then keep some more, and finally
+% drop the end of the string.
+% \begin{macrocode}
+\cs_new_nopar:Npn \str_from_to:Nnn { \exp_args:No \str_from_to:nnn }
+\cs_new:Npn \str_from_to:nnn #1#2#3
+ {
+ \exp_args:Nf \tl_to_str:n
+ { \str_sanitize_args:Nn \str_from_to_unsafe:nnn {#1}{#2}{#3} }
+ }
+\cs_new:Npn \str_from_to_ignore_spaces:nnn #1
+ { \exp_args:No \str_from_to_unsafe:nnn { \tl_to_str:n {#1} } }
+\cs_new:Npn \str_from_to_unsafe:nnn #1#2#3 % <string> <from> <to>
+ {
+ \str_aux_eval_args:Nnnn \str_from_to_aux:nnnw
+ { \str_length_unsafe:n {#1} }
+ {#2}
+ {#3}
+ #1
+ \q_stop
+ }
+\cs_new:Npn \str_from_to_aux:nnnw #1#2#3 % <len> <from> <to>
+ {
+ \exp_args:Nf \str_from_to_aux_ii:nnw
+ { \str_aux_normalize_range:nn {#2} {#1} }
+ { \str_aux_normalize_range:nn {#3} {#1} }
+ }
+\cs_new:Npn \str_from_to_aux_ii:nnw #1#2
+ {
+ \str_skip_do:nn {#1}
+ {
+ \exp_args:Nf \str_collect_do:nn
+ { \int_eval:n { #2 - #1 } }
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ }
+\cs_new:Npn \str_aux_eval_args:Nnnn #1#2#3#4
+ {
+ \exp_after:wN #1
+ \exp_after:wN { \int_value:w \int_eval:w #2 \exp_after:wN }
+ \exp_after:wN { \int_value:w \int_eval:w #3 \exp_after:wN }
+ \exp_after:wN { \int_value:w \int_eval:w #4 }
+ }
+\cs_new:Npn \str_aux_normalize_range:nn #1#2
+ {
+ \int_eval:n
+ {
+ \if_num:w #1 < \c_zero
+ \if_num:w #1 < - #2 \exp_stop_f:
+ \c_zero
+ \else:
+ #1 + #2
+ \fi:
+ \else:
+ \if_num:w #1 < #2 \exp_stop_f:
+ #1
+ \else:
+ #2
+ \fi:
+ \fi:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Internal mapping function}
+%
+% \begin{macro}[rEXP,int]{\str_map_tokens:nn}
+% \begin{macro}[rEXP,int]{\str_map_tokens:Nn}
+% \begin{macro}[rEXP,aux]{\str_map_tokens_aux:nn}
+% \begin{macro}[rEXP,aux]{\str_map_tokens_loop:nN}
+% \begin{macro}[rEXP,int]{\str_map_break_do:n}
+% We simply need to be careful with spaces.
+% Spaces are fed to the mapped tokens with
+% category code $12$, not $10$.
+% \begin{macrocode}
+\cs_new_nopar:Npn \str_map_tokens:Nn
+ { \exp_args:No \str_map_tokens:nn }
+\cs_new_nopar:Npn \str_map_tokens:nn
+ { \str_sanitize_args:Nn \str_map_tokens_aux:nn }
+\cs_new:Npn \str_map_tokens_aux:nn #1#2
+ {
+ \str_map_tokens_loop:nN {#2} #1
+ { ? \use_none_delimit_by_q_recursion_stop:w } \q_recursion_stop
+ }
+\cs_new_nopar:Npn \str_map_tokens_loop:nN #1#2
+ {
+ \use_none:n #2
+ #1 #2
+ \str_map_tokens_loop:nN {#1}
+ }
+\cs_new_eq:NN \str_map_break_do:n \use_i_delimit_by_q_recursion_stop:nw
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{String conditionals}
+%
+% \begin{macro}[EXP,pTF]{\str_if_eq:NN}
+% \begin{macro}[EXP,pTF]{\str_if_eq:nn,\str_if_eq:xx}
+% The \texttt{nn} and \texttt{xx} variants are already
+% defined in \pkg{l3basics}.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \str_if_eq:NN #1#2 { p , TF , T , F }
+ {
+ \if_int_compare:w \pdftex_strcmp:D { \tl_to_str:N #1 } { \tl_to_str:N #2 }
+ = \c_zero \prg_return_true: \else: \prg_return_false: \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP,pTF]{\str_if_contains_char:NN}
+% \begin{macro}[EXP,pTF]{\str_if_contains_char:nN}
+% \begin{macro}[EXP,aux]{\str_if_contains_char_aux:NN}
+% \begin{macro}[EXP,aux]{\str_if_contains_char_end:w}
+% Loop over the characters of the string, comparing character codes.
+% We allow |#2| to be a single-character control sequence, hence the
+% use of \cs{int_compare:nNnT} rather than \cs{token_if_eq_charcode:NNT}.
+% The loop is broken if character codes match. Otherwise we return
+% \enquote{false}.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \str_if_contains_char:NN #1#2 { p , T , F , TF }
+ {
+ \str_map_tokens:Nn #1 { \str_if_contains_char_aux:NN #2 }
+ \prg_return_false:
+ }
+\prg_new_conditional:Npnn \str_if_contains_char:nN #1#2 { p , T , F , TF }
+ {
+ \str_map_tokens:nn {#1} { \str_if_contains_char_aux:NN #2 }
+ \prg_return_false:
+ }
+\cs_new_nopar:Npn \str_if_contains_char_aux:NN #1#2
+ {
+ \if_num:w `#1 = `#2 \exp_stop_f:
+ \str_if_contains_char_end:w
+ \fi:
+ }
+\cs_new_nopar:Npn \str_if_contains_char_end:w \fi: #1 \prg_return_false:
+ { \fi: \prg_return_true: }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP,pTF]{\str_if_bytes:N}
+% \begin{macro}[EXP,aux]{\str_if_bytes_aux:N}
+% Loop over the string, checking if every character code is less than $256$.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \str_if_bytes:N #1 { p , T , F , TF }
+ {
+ \str_map_tokens:Nn #1 { \str_if_bytes_aux:N }
+ \prg_return_true:
+ }
+\cs_new_nopar:Npn \str_if_bytes_aux:N #1
+ {
+ \int_compare:nNnF {`#1} < \c_two_hundred_fifty_six
+ {
+ \use_i_delimit_by_q_recursion_stop:nw
+ { \prg_return_false: \use_none:n }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Internal conditionals}
+%
+% \begin{macro}[aux]{\str_aux_hexadecimal_test:N}
+% This test is used when reading hexadecimal digits, for the |\x| escape
+% sequence, and some conversion functions. It returns \meta{true} if the
+% token is a hexadecimal digit, and \meta{false} otherwise. It has the
+% additional side-effect of updating the value of
+% \cs{l_str_char_int} (number formed in base $16$ from the digits
+% read so far).
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \str_aux_hexadecimal_test:N #1 { TF }
+ {
+ \tl_if_in:onTF { \tl_to_str:n {abcdef} } {#1}
+ {
+ \int_set:Nn \l_str_char_int
+ { \c_sixteen * \l_str_char_int + `#1 - 87 }
+ \prg_return_true:
+ }
+ {
+ \if_num:w \c_fifteen < "1 \exp_not:N #1 \exp_stop_f:
+ \int_set:Nn \l_str_char_int
+ { \c_sixteen * \l_str_char_int + "#1 }
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\str_aux_octal_test:N}
+% This test is used when reading octal digits, for
+% some conversion functions. It returns \meta{true} if the
+% token is an octal digit, and \meta{false} otherwise.
+% It has the additional side-effect of updating the value of
+% \cs{l_str_char_int} (number formed in base $8$ from the digits
+% read so far).
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \str_aux_octal_test:N #1 { TF }
+ {
+ \if_num:w \c_seven < '1 \exp_not:N #1 \exp_stop_f:
+ \int_set:Nn \l_str_char_int
+ { \c_eight * \l_str_char_int + '#1 }
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\str_aux_char_if_octal_digit:NTF}
+% ^^A to be removed.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \str_aux_char_if_octal_digit:NTF #1
+ { \tl_if_in:nnTF { 01234567 } {#1} }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Conversions}
+%
+% \subsubsection{Simple unescaping}
+%
+% The code of this section is used both here for \cs{str_(g)input:Nn},
+% and in the regular expression module to go through the regular expression
+% once before actually parsing it. The goal in that case is to turn any
+% character with a meaning in regular expressions (\texttt{*}, \texttt{?},
+% \texttt{\{}, etc.) into a marker indicating that this was a special character,
+% and replace any escaped character by the corresponding unescaped character,
+% so that the \pkg{l3regex} code can avoid caring about escaping issues
+% (those can become quite complex to handle in combination with ranges
+% in character classes).
+%
+% The idea is to feed unescaped characters to one function,
+% escaped characters to another, and feed |\a|, |\e|, |\f|,
+% |\n|, |\r|, |\t| and |\x| converted to the approriate
+% character to a third function. Spaces are ignored unless
+% escaped.
+% For the \cs{str_(g)input:Nn} application, all the functions are simply
+% \cs{token_to_str:N} (this ensures that spaces correctly get assigned
+% category code $10$).
+% For the \pkg{l3regex} applications, the functions do some further
+% tests on the character they receive.
+%
+% \begin{macro}{\str_input:Nn,\str_ginput:Nn}
+% Simple wrappers around the internal \cs{str_aux_escape:NNNn}.
+% \begin{macrocode}
+\cs_new_protected:Npn \str_input:Nn #1#2
+ {
+ \str_aux_escape:NNNn \token_to_str:N \token_to_str:N \token_to_str:N {#2}
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected:Npn \str_ginput:Nn #1#2
+ {
+ \str_aux_escape:NNNn \token_to_str:N \token_to_str:N \token_to_str:N {#2}
+ \tl_gset_eq:NN #1 \g_str_result_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\str_aux_escape:NNNn}
+% \begin{macro}[aux]{\str_aux_escape_unescaped:N}
+% \begin{macro}[aux]{\str_aux_escape_escaped:N}
+% \begin{macro}[aux]{\str_aux_escape_raw:N}
+% \begin{macro}[aux]{\str_aux_escape_loop:N}
+% \begin{macro}[aux]+\str_aux_escape_\:w+
+% Treat the argument as an \meta{escaped string},
+% and store the corresponding \meta{string} globally
+% in \cs{g_str_result_tl}.
+% \begin{macrocode}
+\cs_new_eq:NN \str_aux_escape_unescaped:N \use:n
+\cs_new_eq:NN \str_aux_escape_escaped:N \use:n
+\cs_new_eq:NN \str_aux_escape_raw:N \use:n
+\cs_new_protected:Npn \str_aux_escape:NNNn #1#2#3#4
+ {
+ \group_begin:
+ \cs_set_nopar:Npn \str_aux_escape_unescaped:N { #1 }
+ \cs_set_nopar:Npn \str_aux_escape_escaped:N { #2 }
+ \cs_set_nopar:Npn \str_aux_escape_raw:N { #3 }
+ \int_set:Nn \tex_escapechar:D {92}
+ \tl_gset:Nx \g_str_result_tl { \tl_to_other_str:n {#4} }
+ \tl_gset:Nx \g_str_result_tl
+ {
+ \exp_after:wN \str_aux_escape_loop:N \g_str_result_tl
+ \q_recursion_tail \q_recursion_stop
+ }
+ \group_end:
+ }
+\cs_new_nopar:Npn \str_aux_escape_loop:N #1
+ {
+ \cs_if_exist_use:cF { str_aux_escape_\token_to_str:N #1:w }
+ { \str_aux_escape_unescaped:N #1 }
+ \str_aux_escape_loop:N
+ }
+\cs_new_nopar:cpn { str_aux_escape_ \c_backslash_str :w }
+ \str_aux_escape_loop:N #1
+ {
+ \cs_if_exist_use:cF { str_aux_escape_/\token_to_str:N #1:w }
+ { \str_aux_escape_escaped:N #1 }
+ \str_aux_escape_loop:N
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]+\str_aux_escape_\q_recursion_tail:w+
+% \begin{macro}[aux]+\str_aux_escape_/\q_recursion_tail:w+
+% \begin{macro}[aux]+\str_aux_escape_ :w+
+% \begin{macro}[aux]{
+% \str_aux_escape_/a:w, \str_aux_escape_/e:w, \str_aux_escape_/f:w,
+% \str_aux_escape_/n:w, \str_aux_escape_/r:w, \str_aux_escape_/t:w}
+% The loop is ended upon seeing \cs{q_recursion_tail}.
+% Spaces are ignored, and |\a|, |\e|, |\f|, |\n|, |\r|, |\t| take
+% their meaning here.
+% \begin{macrocode}
+\cs_new_eq:cN
+ { str_aux_escape_ \c_backslash_str q_recursion_tail :w }
+ \use_none_delimit_by_q_recursion_stop:w
+\cs_new_eq:cN
+ { str_aux_escape_ / \c_backslash_str q_recursion_tail :w }
+ \use_none_delimit_by_q_recursion_stop:w
+\cs_new_nopar:cpn { str_aux_escape_~:w } { }
+\cs_new_nopar:cpx { str_aux_escape_/a:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^G }
+\cs_new_nopar:cpx { str_aux_escape_/t:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^I }
+\cs_new_nopar:cpx { str_aux_escape_/n:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^J }
+\cs_new_nopar:cpx { str_aux_escape_/f:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^L }
+\cs_new_nopar:cpx { str_aux_escape_/r:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^M }
+\cs_new_nopar:cpx { str_aux_escape_/e:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^[ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\str_aux_escape_/x:w}
+% \begin{macro}[aux]{\str_aux_escape_x_test:N}
+% \begin{macro}[aux]{\str_aux_escape_x_unbraced_i:N}
+% \begin{macro}[aux]{\str_aux_escape_x_unbraced_ii:N}
+% \begin{macro}[aux]{\str_aux_escape_x_braced_loop:N}
+% \begin{macro}[aux]{\str_aux_escape_x_braced_end:N}
+% \begin{macro}[aux]{\str_aux_escape_x_end:}
+% When |\x| is encountered, interrupt the assignment,
+% and distinguish the cases of a braced or unbraced syntax.
+% In the braced case, collect arbitrarily many hexadecimal digits,
+% building the number in \cs{l_str_char_int} (this is a side effect
+% of \cs{str_aux_hexadecimal_test:NTF}), and check that
+% the run of digits was interrupted by a closing brace.
+% In the unbraced case, collect up to two hexadecimal digits,
+% possibly less, building the character number in \cs{l_str_char_int}.
+% In both cases, once all digits have been collected, use
+% the \TeX{} primitive \tn{lowercase} to produce that character,
+% and use a \cs{if_false:} trick to restart the assignment.
+% \begin{macrocode}
+\cs_new_nopar:cpn { str_aux_escape_/x:w } \str_aux_escape_loop:N
+ {
+ \if_false: { \fi: }
+ \int_zero:N \l_str_char_int
+ \str_aux_escape_x_test:N
+ }
+\cs_new_protected_nopar:Npx \str_aux_escape_x_test:N #1
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_space_token #1
+ { \exp_not:N \str_aux_escape_x_test:N }
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_lbrace_str #1
+ { \exp_not:N \str_aux_escape_x_braced_loop:N }
+ { \exp_not:N \str_aux_escape_x_unbraced_i:N #1 }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_unbraced_i:N #1
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_unbraced_ii:N }
+ { \str_aux_escape_x_end: #1 }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_unbraced_ii:N #1
+ {
+ \token_if_eq_charcode:NNTF \c_space_token #1
+ { \str_aux_escape_x_unbraced_ii:N }
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_end: }
+ { \str_aux_escape_x_end: #1 }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_braced_loop:N #1
+ {
+ \token_if_eq_charcode:NNTF \c_space_token #1
+ { \str_aux_escape_x_braced_loop:N }
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_braced_loop:N }
+ { \str_aux_escape_x_braced_end:N #1 }
+ }
+ }
+\cs_new_protected_nopar:Npx \str_aux_escape_x_braced_end:N #1
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_rbrace_str #1
+ { \exp_not:N \str_aux_escape_x_end: }
+ {
+ \msg_error:nn { str } { x-missing-brace }
+ \exp_not:N \str_aux_escape_x_end: #1
+ }
+ }
+\group_begin:
+ \char_set_catcode_other:N \^^@
+ \cs_new_protected_nopar:Npn \str_aux_escape_x_end:
+ {
+ \group_begin:
+ \char_set_lccode:nn { \c_zero } { \l_str_char_int }
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \tl_gput_right:Nx \g_str_result_tl
+ { \if_false: } \fi:
+ \str_aux_escape_raw:N ^^@
+ \str_aux_escape_loop:N
+ }
+ }
+\group_end:
+\msg_new:nnn { str } { x-missing-brace }
+ {
+ You~wrote~something~like~
+ `\iow_char:N\\x\{ \int_to_hexadecimal:n { \l_str_char_int }'.~
+ The~closing~brace~is~missing.
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Escape and unescape strings for pdf use}
+%
+% \begin{macro}{\str_aux_convert_store:}
+% \begin{macro}{\str_aux_convert_store:NNn}
+% \begin{macrocode}
+\group_begin:
+ \char_set_catcode_other:n {`\^^@}
+ \cs_new_protected_nopar:Npn \str_aux_convert_store:
+ {
+ \char_set_lccode:nn {\c_zero} {\l_str_char_int}
+ \tl_to_lowercase:n { \tl_gput_right:Nx \g_str_result_tl {^^@} }
+ }
+ \cs_new_protected_nopar:Npn \str_aux_convert_store:NNn #1#2#3
+ {
+ \char_set_lccode:nn {\c_zero} {#3}
+ \tl_to_lowercase:n { #1 #2 {^^@} }
+ }
+\group_end:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\str_aux_byte_to_hexadecimal:N}
+% \begin{macro}{\str_aux_byte_to_octal:N}
+% \begin{macrocode}
+\cs_new_nopar:Npn \str_aux_byte_to_hexadecimal:N #1
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ {
+ \int_to_letter:n { \int_div_truncate:nn {`#1} \c_sixteen }
+ \int_to_letter:n { \int_mod:nn {`#1} \c_sixteen }
+ }
+ { \msg_expandable_error:n { Invalid~byte~`#1'. } }
+ }
+\cs_new_nopar:Npn \str_aux_byte_to_octal:N #1
+ {
+ \int_compare:nNnTF {`#1} < {64}
+ {
+ 0
+ \int_to_letter:n { \int_div_truncate:nn {`#1} \c_eight }
+ \int_to_letter:n { \int_mod:nn {`#1} \c_eight }
+ }
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ { \int_to_octal:n {`#1} }
+ { \msg_expandable_error:n { Invalid~byte~`#1'. } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\str_bytes_escape_hexadecimal:NN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \str_bytes_escape_hexadecimal:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_aux_byte_to_hexadecimal:N }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\str_bytes_escape_name:NN}
+% \begin{macrocode}
+\tl_const:Nx \c_str_bytes_escape_name_str
+ { \c_hash_str \c_percent_str \c_lbrace_str \c_rbrace_str () /<>[] }
+\cs_new_protected_nopar:Npn \str_bytes_escape_name:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_escape_name_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_escape_name_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"21}
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_escape_name_str #1
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {#1}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\str_bytes_escape_string:NN}
+% Any character below (and including) space, and any character
+% above (anc including) \texttt{del}, are converted to octal.
+% One backslash is added before each parenthesis and backslash.
+% \begin{macrocode}
+\tl_const:Nx \c_str_bytes_escape_string_str { \c_backslash_str ( ) }
+\cs_new_protected_nopar:Npn \str_bytes_escape_string:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_escape_string_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_escape_string_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"21}
+ { \c_backslash_str \str_aux_byte_to_octal:N #1 }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_backslash_str \str_aux_byte_to_octal:N #1 }
+ {
+ \str_if_contains_char:NNT \c_str_bytes_escape_string_str #1
+ { \c_backslash_str }
+ #1
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\str_bytes_unescape_hexadecimal:NN}
+% \begin{macro}[aux]{\str_bytes_unescape_hexadecimal_aux:N}
+% \begin{macro}[aux]{\str_bytes_unescape_hexadecimal_aux_ii:N}
+% Takes chars two by two, and interprets each pair as a hexadecimal code
+% for a character. Any non-hexadecimal-digit is ignored. An odd-length
+% string gets a |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_nopar:Npn \str_bytes_unescape_hexadecimal:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \int_zero:N \l_str_char_int
+ \exp_last_unbraced:Nf \str_bytes_unescape_hexadecimal_aux:N
+ { \tl_to_other_str:N #2 } 0
+ \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_hexadecimal_aux:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_bytes_unescape_hexadecimal_aux_ii:N }
+ { \str_bytes_unescape_hexadecimal_aux:N }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_hexadecimal_aux_ii:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \str_aux_hexadecimal_test:NTF #1
+ {
+ \str_aux_convert_store:
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_hexadecimal_aux:N
+ }
+ { \str_bytes_unescape_hexadecimal_aux_ii:N }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\str_bytes_unescape_name:NN}
+% \begin{macro}[aux]{\str_bytes_unescape_name_aux:wN}
+% \begin{macro}[aux]{\str_bytes_unescape_name_aux_ii:N}
+% This changes all occurrences of |#| followed by two upper- or lowercase
+% hexadecimal digits by the corresponding unescaped character.
+% \begin{macrocode}
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\#}
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_name:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \int_zero:N \l_str_char_int
+ \exp_last_unbraced:Nf \str_bytes_unescape_name_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_name_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \str_aux_hexadecimal_test:NTF #2
+ { \str_bytes_unescape_name_aux_ii:NN #2 }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_hash_str }
+ \str_bytes_unescape_name_aux:wN #2
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_name_aux_ii:NN #1#2
+ {
+ \str_aux_hexadecimal_test:NTF #2
+ {
+ \str_aux_convert_store:
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_name_aux:wN
+ }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_hash_str #1 }
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_name_aux:wN #2
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\str_bytes_unescape_string:NN}
+% Here, we need to detect backslashes, which escape characters
+% as follows.
+% \begin{itemize}
+% \item[\texttt{\string\n}] Line feed ($10$)
+% \item[\texttt{\string\r}] Carriage return ($13$)
+% \item[\texttt{\string\t}] Horizontal tab ($9$)
+% \item[\texttt{\string\b}] Backspace ($8$)
+% \item[\texttt{\string\f}] Form feed ($12$)
+% \item[\texttt{(}] Left parenthesis
+% \item[\texttt{)}] Right parenthesis
+% \item[\texttt{\string\\}] Backslash
+% \item[\texttt{\string\ddd}] Character code \texttt{ddd} (octal)
+% \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.
+% The pdf specification indicates that LF, CR, and CRLF should be
+% converted to LF: \emph{this is not implemented here}.
+% \begin{macrocode}
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\\}
+ \char_set_catcode_other:N \^^J
+ \char_set_catcode_other:N \^^M
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_string:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_bytes_unescape_string_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \int_zero:N \l_str_char_int
+ \str_aux_octal_test:NTF #2
+ { \str_bytes_unescape_string_aux_d:N }
+ {
+ \int_set:Nn \l_str_char_int
+ {
+ \prg_case_str:xxn {#2}
+ {
+ {n} {10}
+ {r} {13}
+ {t} {9}
+ {b} {8}
+ {f} {12}
+ {(} {40}
+ {)} {41}
+ {\c_backslash_str} {92}
+ {^^J} {-1}
+ {^^M} {-1}
+ }
+ {`#2}
+ }
+ \int_compare:nNnF \l_str_char_int = \c_minus_one
+ { \str_aux_convert_store: }
+ \str_bytes_unescape_string_aux:wN
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux_d:N #1
+ {
+ \str_aux_octal_test:NTF #1
+ { \str_bytes_unescape_string_aux_dd:N }
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN #1
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux_dd:N #1
+ {
+ \str_aux_octal_test:NTF #1
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN
+ }
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN #1
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Percent encoding}
+%
+% \begin{macro}{\str_bytes_percent_encode:NN}
+% \begin{macrocode}
+\tl_const:Nx \c_str_bytes_percent_encode_str { \tl_to_str:n { [] } }
+\tl_const:Nx \c_str_bytes_percent_encode_not_str { \tl_to_str:n { "-.<> } }
+\cs_new_protected_nopar:Npn \str_bytes_percent_encode:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_percent_encode_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_percent_encode_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"41}
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_percent_encode_not_str #1
+ { #1 }
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_percent_encode_str #1
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ { #1 }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\str_bytes_percent_decode:NN}
+% \begin{macro}[aux]{\str_bytes_percent_decode_aux:wN}
+% \begin{macro}[aux]{\str_bytes_percent_decode_aux_ii:NN}
+% \begin{macrocode}
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\%}
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_percent_decode:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_bytes_percent_decode_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_percent_decode_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \int_zero:N \l_str_char_int
+ \str_aux_hexadecimal_test:NTF #2
+ { \str_bytes_percent_decode_aux_ii:NN #2 }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_percent_str }
+ \str_bytes_percent_decode_aux:wN #2
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_percent_decode_aux_ii:NN #1#2
+ {
+ \str_aux_hexadecimal_test:NTF #2
+ {
+ \str_aux_convert_store:
+ \str_bytes_percent_decode_aux:wN
+ }
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \str_bytes_percent_decode_aux:wN #2
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{UTF-8 support}
+%
+% \begin{macro}{\str_native_from_UTF_viii:NN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \str_native_from_UTF_viii:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_native_from_UTF_viii_aux_i:N
+ { \tl_to_other_str:N #2 }
+ \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_native_from_UTF_viii_aux_i:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \int_set:Nn \l_str_char_int { `#1 }
+ \str_native_from_UTF_viii_aux_ii:nN {128} \c_one
+ \str_native_from_UTF_viii_aux_ii:nN {64} \c_zero
+ \str_native_from_UTF_viii_aux_ii:nN {32} \c_two
+ \str_native_from_UTF_viii_aux_ii:nN {16} \c_three
+ \str_native_from_UTF_viii_aux_ii:nN {8} \c_four
+ \msg_error:nnx { str } { utf8-invalid-byte } {#1}
+ \use_i:nnn \str_native_from_UTF_viii_aux_i:N
+ \q_stop
+ \str_native_from_UTF_viii_aux_iii:N
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_ii:nN #1#2
+ {
+ \int_compare:nNnTF \l_str_char_int < {#1}
+ {
+ \int_set_eq:NN \l_str_bytes_int #2
+ \use_none_delimit_by_q_stop:w
+ }
+ { \int_sub:Nn \l_str_char_int {#1} }
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_iii:N #1
+ {
+ \int_compare:nNnTF \l_str_bytes_int < \c_two
+ { \str_native_from_UTF_viii_aux_iv: #1 }
+ {
+ \if_meaning:w \q_recursion_tail #1
+ \msg_error:nn { str } { utf8-premature-end }
+ \exp_after:wN \use_none_delimit_by_q_recursion_stop:w
+ \fi:
+ \quark_if_recursion_tail_stop:N #1
+ \tex_multiply:D \l_str_char_int by 64 \scan_stop: % no interface??
+ \int_decr:N \l_str_bytes_int
+ \int_compare:nNnTF {`#1} < {128}
+ { \use_ii:nn }
+ { \int_compare:nNnTF {`#1} < {192} }
+ {
+ \int_add:Nn \l_str_char_int { `#1 - 128 }
+ \str_native_from_UTF_viii_aux_iii:N
+ }
+ {
+ \msg_error:nnx { str } { utf8-missing-byte } {#1}
+ \str_native_from_UTF_viii_aux_i:N #1
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_iv:
+ {
+ \int_compare:nNnTF \l_str_bytes_int = \c_zero
+ {
+ \msg_error:nnx { str } { utf8-extra-byte }
+ { \int_eval:n { \l_str_char_int + 128 } }
+ }
+ {
+ \pdftex_if_engine:TF
+ {
+ \int_compare:nNnTF { \l_str_char_int } < { 256 }
+ { \str_aux_convert_store: }
+ {
+ \msg_error:nnx { str } { utf8-pdftex-overflow }
+ { \int_use:N \l_str_char_int }
+ }
+ }
+ { \str_aux_convert_store: }
+ }
+ \str_native_from_UTF_viii_aux_i:N
+ }
+\msg_new:nnn { str } { utf8-invalid-byte }
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ { Byte~number~\int_eval:n {`#1}~invalid~in~utf-8~encoding. }
+ { The~character~number~\int_eval:n {`#1}~is~not~a~byte. }
+ }
+\msg_new:nnn { str } { utf8-missing-byte }
+ { The~byte~number~\int_eval:n {`#1}~is~not~a~valid~continuation~byte. }
+\msg_new:nnn { str } { utf8-extra-byte }
+ { The~byte~number~\int_eval:n {`#1}~is~only~valid~as~a~continuation~byte. }
+\msg_new:nnnn { str } { utf8-premature-end }
+ { Incomplete~last~utf8~character. }
+ {
+ The~sequence~of~byte~that~I~need~to~convert~to~utf8 \
+ ended~before~the~last~character~was~complete.~Perhaps \
+ it~was~mistakenly~truncated?
+ }
+\msg_new:nnn { str } { utf8-pdftex-overflow }
+ { The~character~number~#1~is~too~big~for~pdfTeX. }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\str_UTF_viii_from_native:NN}
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \str_map_tokens:Nn #2 \str_UTF_viii_from_native_aux_i:N
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native_aux_i:N #1
+ {
+ \int_set:Nn \l_str_char_int {`#1}
+ \int_compare:nNnTF \l_str_char_int < {128}
+ { \tl_gput_right:Nx \g_str_result_tl {#1} }
+ {
+ \tl_gclear:N \g_str_tmpa_tl
+ \int_set:Nn \l_str_bytes_int { 64 }
+ \str_UTF_viii_from_native_aux_ii:n {32}
+ \str_UTF_viii_from_native_aux_ii:n {16}
+ \str_UTF_viii_from_native_aux_ii:n {8}
+ \ERROR % somehow the unicode char was > "1FFFFF > "10FFFF
+ \tl_gclear:N \g_str_tmpa_tl
+ \use_none:n \q_stop
+ \int_add:Nn \l_str_char_int { 2 * \l_str_bytes_int }
+ \str_aux_convert_store:
+ \tl_gput_right:Nx \g_str_result_tl { \g_str_tmpa_tl }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native_aux_ii:n #1
+ {
+ \str_aux_convert_store:NNn
+ \tl_gput_left:Nx \g_str_tmpa_tl
+ { 128 + \int_mod:nn { \l_str_char_int } {64} }
+ \tex_divide:D \l_str_char_int by 64 \scan_stop: % no interface??
+ \int_add:Nn \l_str_bytes_int {#1}
+ \int_compare:nNnT \l_str_char_int < {#1}
+ { \use_none_delimit_by_q_stop:w }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Deprecated string functions}
+%
+% \begin{macro}{\str_length_skip_spaces:N,\str_length_skip_spaces:n}
+% The naming scheme is a little bit more consistent
+% with \enquote{ignore_spaces} instead of \enquote{skip_spaces}.
+% \begin{macrocode}
+\cs_gset:Npn \str_length_skip_spaces:N
+ { \exp_args:No \str_length_skip_spaces:n }
+\cs_gset_eq:NN \str_length_skip_spaces:n \str_length_ignore_spaces:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins
new file mode 100644
index 00000000000..5aef8b5f0fe
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins
@@ -0,0 +1,43 @@
+\iffalse meta-comment
+
+File l3str.ins Copyright (C) 2011 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 released version of this bundle is available from CTAN.
+
+\fi
+
+\input docstrip.tex
+\askforoverwritefalse
+
+\preamble
+
+EXPERIMENTAL CODE
+
+Do not distribute this file without also distributing the
+source files specified above.
+
+Do not distribute a modified version of this file.
+
+\endpreamble
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+
+\keepsilent
+
+\generate{\file{l3str.sty} {\from{l3str.dtx} {package}}}
+\generate{\file{l3regex.sty} {\from{l3regex.dtx} {package}}}
+
+\generate{\file{l3regex-trace.sty} {\from{l3regex.dtx} {package,trace}}}
+
+\endbatchfile
diff --git a/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx b/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx
index ca25807a810..103934d5fe8 100644
--- a/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/xcoffins/xcoffins.dtx
@@ -36,7 +36,7 @@
%
%<*driver|package>
\RequirePackage{xparse}
-\GetIdInfo$Id: xcoffins.dtx 2349 2011-05-11 18:44:37Z joseph $
+\GetIdInfo$Id: xcoffins.dtx 2895 2011-10-09 15:58:19Z joseph $
{L3 Experimental design-level coffins}
%</driver|package>
%<*driver>
@@ -298,9 +298,9 @@
% \begin{syntax}
% \cs{RotateCoffin} \meta{coffin} \Arg{angle}
% \end{syntax}
-% Rotates the \meta{coffin} by the given \meta{angle} (given in
-% degrees counter-clockwise). This process will rotate both the
-% coffin content and poles. Multiple rotations will not result in
+% Rotates the \meta{coffin} by the given \meta{angle} about its reference
+% point (given in degrees counter-clockwise) . This process will rotate both
+% the coffin content and poles. Multiple rotations will not result in
% the bounding box of the coffin growing unnecessarily.
%
% The effect of rotation on a coffin is illustrated in
@@ -474,13 +474,13 @@
% \hfil
% \begin{minipage}{0.4\textwidth}
% \centering
-% \fbox{\TypesetCoffin\ExampleCoffin}
+% \fbox{\copy\ExampleCoffin}
% \end{minipage}
% \hfil
% \begin{minipage}{0.4\textwidth}
% \centering
% \RotateCoffin\ExampleCoffin{135}
-% \fbox{\TypesetCoffin\ExampleCoffin}
+% \fbox{\copy\ExampleCoffin}
% \end{minipage}
% \hfil
% \caption{The effect of rotation of a joined coffin: the black line
diff --git a/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx b/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx
new file mode 100644
index 00000000000..fa54ac37e59
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx
@@ -0,0 +1,2140 @@
+% \iffalse
+%
+%% File: l3galley.dtx Copyright (C) 1999-2001, 2004-2009 Frank Mittelbach
+%% (C) 2010,2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX Project Team.
+%%
+%% -----------------------------------------------------------------------
+%%
+%
+%<*driver|package>
+\RequirePackage{l3names}
+\GetIdInfo$Id: l3galley.dtx 2899 2011-10-09 21:22:06Z joseph $
+ {L3 Experimental galley code}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \textsf{l3galley} package\\ Galley code^^A
+% \thanks{This file describes v\ExplFileVersion,
+% last revised \ExplFileDate.}^^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 \ExplFileDate}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \section{Introduction}
+%
+% In \LaTeX3 terminology a galley is a rectangular area which receives
+% text and other material filling it from top. The vertically extend of
+% a galley is normally not restricted: instead certain chunks are taken
+% off the top of an already partially filled galley to form columns or
+% similar areas on a page. This process is typically asynchronous but
+% there are ways to control or change its behaviour.
+%
+% Examples for galleys are \enquote{the main galley}, where the
+% continuous document data gets formatted into and from which columns
+% and pages are constructed, and \enquote{vertical box galleys}, such
+% as the body of a minipage environment. The latter galleys are
+% typically not split after formatting, though there can be exceptions.
+%
+% \section{Formatting layers}
+%
+% The present module is mainly concerned with the formatting of text
+% in galleys. The mechanism by which this is achieved uses four
+% (somewhat) distinct layers, some of which can be addressed using the
+% templates provided here.
+%
+% \subsection{Layer one: external dimensions}
+%
+% The bottom layer of the system is the external dimensions of the
+% galley. Normally only the horizontal dimension is fixed externally,
+% while the vertical (filling) dimension is unspecified. The external
+% dimensions are fixed when starting a new galley, and are therefore
+% not modifiable within the galley.
+%
+% There are no templates for setting this layer directly, although the
+% external values are influenced by other parts of the system (for
+% example when creating minipage environments).
+%
+% \subsection{Layer two: internal dimensions}
+%
+% The second layer is the internal dimensions of the galley: the
+% \emph{measure} used for paragraph text and the position of the
+% paragraph relative to the edges of the galley.
+%
+% This layer is normally accessed by higher-level templates
+% \emph{via} the object type \texttt{measure}. Changes made using
+% level two templates will often extend for large parts of a document
+% (up to and including the entire document).
+%
+% \subsection{Layer three: paragraph shape}
+%
+% The third layer defines the paragraph shape within the measure as
+% provided by the second layer. In the absence of any specification
+% for that layer the paragraph shape used will be that of a
+% rectangular area of the width of the current measure.
+%
+% There are some restrictions imposed on the shape of a paragraph by the
+% underlying \TeX{} mechanisms. For example, cut out sections in
+% paragraphs can be specified from the top of the paragraph but not from
+% the bottom.
+%
+% \subsection{Layer four: formatting inside the paragraph}
+%
+% The forth layer deals with the paragraph formatting aspects such as
+% hyphenation and justification within the paragraph (this is sometimes
+% referred to as \enquote{\texttt{h\&j}} or \enquote{\texttt{hj}}). This
+% layer is somewhat distinct from the galley as such, but is handled in
+% the same place as there is, internally, interaction between the different
+% layers.
+%
+% \section{Code interfaces}
+%
+% \subsection{Galley layers}
+%
+% \begin{variable}{\l_galley_width_dim}
+% The total width of a galley, set either by the page geometry code
+% for the main vertical galley or when creating an independent galley,
+% such as a minipage.
+% \end{variable}
+%
+% \begin{function}{\galley_level:}
+% \begin{syntax}
+% \cs{galley_level:}
+% \end{syntax}
+% Sets up a vertical box to contain a new galley level. The box should
+% be \enquote{colour safe}, which is automatic for \LaTeX3 coffins but
+% must be included manually (using \cs{color_group_begin:} and
+% \cs{color_group_end:}) in \enquote{raw} vertical boxes.
+% \end{function}
+%
+% \subsection{Measure}
+%
+% \begin{function}
+% {\galley_margins_set_absolute:nn, \galley_margins_set_relative:nn}
+% \begin{syntax}
+% \cs{galley_margins_set_absolute:nn} \Arg{left margin} \Arg{right margin}
+% \cs{galley_margins_set_relative:nn} \Arg{left margin} \Arg{right margin}
+% \end{syntax}
+% Sets the width of the measure to have the \meta{left margin} and
+% \meta{right margin} specified by the arguments, both of which are
+% \meta{dimension expressions}. The \texttt{relative} function will adjust
+% the text width within any existing margins, whereas the \texttt{absolute}
+% measure sets the margins based on the edges of the galley only. One or
+% both of the \meta{margins} may be negative, to specify and outdent.
+% \end{function}
+%
+% \subsection{Between paragraphs}
+%
+% \begin{variable}{\g_galley_restore_running_tl}
+% When galley settings need to be reset at the end of a paragraph, the
+% appropriate detail should be added to this token list. It is inserted
+% immediately before the start of each paragraph, and can therefore be
+% used to clear otherwise global settings. The token list itself is
+% also cleared as part of this process.
+% \end{variable}
+%
+% \begin{variable}{\g_galley_no_break_next_bool}
+% Indicates that no page break should be allowed between the current
+% paragraph and the next paragraph.
+% \end{variable}
+%
+% \begin{function}{\g_galley_omit_next_indent_bool}
+% Indicates that the indent should be omitted from the start of the next
+% paragraph started.
+% \end{function}
+%
+% \begin{variable}{\l_galley_interpar_penalty_int}
+% The \meta{penalty} for a break between paragraphs. The \meta{penalty}
+% should be in the range $-10\,000$ to $10\,000$, where $-10\,000$ forces a
+% page break, $0$ has no effect at all and $10\,000$ forbids a page break.
+% Note that setting \cs{g_galley_no_break_next_bool} to \texttt{true}
+% will override any setting of \cs{l_galley_interpar_penalty_int}.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_interpar_vspace_skip}
+% Stretchable space to be inserted between paragraphs, set at the design
+% or template level.
+% \end{variable}
+%
+% \begin{function}{\galley_set_user_penalty:n}
+% \begin{syntax}
+% \cs{galley_set_user_penalty:n} \Arg{penalty}
+% \end{syntax}
+% Sets the \meta{penalty} for a break between the current and next
+% paragraph on a one-off basis. This function is intended for user-level
+% adjustments to design, and takes precedent over both settings from
+% \cs{galley_set_penalty:n} and from \cs{galley_no_break_next:}.
+% \end{function}
+%
+% \begin{function}{\galley_set_user_vspace:n}
+% \begin{syntax}
+% \cs{galley_set_user_vspace:n} \Arg{space}
+% \end{syntax}
+% Sets the \meta{space} f to be inserted between the current and next
+% paragraph on a one-off basis. This function is intended for user-level
+% adjustments to design, and otherwise is analogous to
+% \cs{galley_set_vspace:n}.
+% \end{function}
+%
+% \subsection{Paragraph shape}
+%
+% \begin{function}
+% {
+% \galley_parshape_multi_par:nnnN,
+% \galley_parshape_multi_par:nVVN,
+% \galley_parshape_single_par:nnnN,
+% \galley_parshape_single_par:nVVN
+% }
+% \begin{syntax}
+% \cs{galley_parshape_multi_par:nnnN} \Arg{unaltered lines} \Arg{left indents} \Arg{right indents} \meta{resume flag}
+% \cs{galley_parshape_single_par:nnnN} \Arg{unaltered lines} \Arg{left indents} \Arg{right indents} \meta{resume flag}
+% \end{syntax}
+% Sets the current paragraph shape to create an arbitrary paragraph shape.
+% The paragraph shape is set such that there are \meta{unaltered lines} which
+% have width and indent as set by the measure. The \enquote{altered} lines
+% are then defined by the comma-separated lists of \meta{left indents} and
+% \meta{right indents}. These are both indents from the edge of the measure,
+% and may be negative, and should both contain the same number of items.
+% If the \meta{resume flag} is \texttt{true}, after the last
+% altered line the paragraph shape returns to that of the measure. On the
+% other hand, if the flag is \texttt{false} then the shape of the last line
+% is retained for the rest of the paragraph.
+% For example,
+% \begin{verbatim}
+% \galley_parshape_set_multi_par:nnnN { 1 }
+% { 2 pt , 4 pt , 6 pt } { 2 pt , 4 pt , 6 pt } \c_true_bool
+% \end{verbatim}
+% would create a paragraph shape in which the first line is the full
+% width of the measure, the second line is indented by $2$\,pt on each side,
+% the third line by by $4$\,pt and the fourth line and subsequent lines by
+% $6$\,pt from the edge of the measure on each side.
+%
+% The \texttt{single_par} version applies only to a single paragraph,
+% while the \texttt{multi_par} function sets the paragraph shape on an
+% ongoing basis within the scope of the current \TeX{} group.
+% \end{function}
+%
+% \begin{function}
+% {
+% \galley_parshape_fixed_lines:nnn,
+% \galley_parshape_fixed_lines:nVV
+% }
+% \begin{syntax}
+% \cs{galley_parshape_fixed_lines:nnn} \Arg{unaltered lines} \Arg{left indents} \Arg{right indents}
+% \end{syntax}
+% Sets the paragraph shape to create an arbitrary paragraph shape which will
+% apply to an exact number of lines.
+% The paragraph shape is set such that there are \meta{unaltered lines} which
+% have width and indent as set by the measure. The \enquote{altered} lines
+% are then defined by the comma-separated lists of \meta{left indents} and
+% \meta{right indents}. These are both indents from the edge of the measure,
+% and may be negative, and should both contain the same number of items.
+% The altered lines will apply to one or more paragraphs, such that the
+% entire indent specification is honoured before the standard measure
+% resumes.
+% \end{function}
+%
+% \subsection{Formatting inside the paragraph}
+%
+% The settings described here apply \enquote{inside} the paragraph, and so
+% are active irrespective of any paragraph shape within the measure.
+%
+% \begin{variable}{\l_galley_line_left_skip, \l_galley_line_right_skip}
+% Stretchable space added to the appropriate side each line in a paragraph.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_par_begin_skip, \l_galley_par_end_skip}
+% Stretchable space added to the beginning of the first line and end of
+% the last line of a paragraph, respectively.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_par_indent_dim}
+% Fixed space added to the start of each paragraph except for those where
+% \cs{l_galley_omit_next_indent_bool} is \texttt{true}.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_last_line_fit_int}
+% Determines how the inter-word stretch is set for the last line of a
+% paragraph when
+% \begin{enumerate}
+% \item The value of \cs{l_galley_par_end_skip} contains an infinite
+% (\texttt{fil}) component;
+% \item The values of \cs{l_galley_line_left_skip} and
+% \cs{l_galley_line_right_skip} do \emph{not} contain an infinite
+% (\texttt{fil}) component.
+% \end{enumerate}
+% Under these circumstances, \cs{l_galley_last_line_fit_int} is active, and
+% applies as follows:
+% \begin{itemize}
+% \item Set to $0$, the last line of the paragraph is set with
+% the inter-word spacing at natural width;
+% \item Set to a $1000$ (or above), the inter-word spacing in the last line
+% is stretched by the same factor as that applied to the penultimate
+% line;
+% \item Set to $n$ between these extremes, the inter-word spacing in the
+% last line is stretched by $n/1000$ times the factor used for the
+% penultimate line.
+% \end{itemize}
+% \end{variable}
+%
+% \begin{function}{\galley_set_interword_spacing:N}
+% \begin{syntax}
+% \cs{galley_set_interword_spacing:N} \meta{fixed spacing bool}
+% \end{syntax}
+% Sets the inter-word spacing used based on the values supplied by the
+% current font. If the \meta{fixed spacing bool} flag is \texttt{true} then
+% no stretch is permitted between words, otherwise the stretch specified by
+% the font designer is used.
+% \end{function}
+%
+% \subsection{Display material}
+%
+% Material which is set in \enquote{display-style} require additional settings
+% to control the relationship with the surrounding material.
+%
+% \begin{function}{\galley_display_begin:, \galley_display_end:}
+% \begin{syntax}
+% \cs{galley_display_begin:}
+% \ldots
+% \cs{galley_display_end:}
+% \end{syntax}
+% Sets up a group to contain display-style material. Unlike an independent
+% galley level, settings are inherited from the surroundings. However,
+% the interaction of a display block with the paragraphs before and after it
+% can be adjusted independent of the design of text.
+% \end{function}
+%
+% \subsection{Line breaking}
+%
+% \begin{variable}{\l_galley_binop_penalty_int}
+% Penalty charged if an inline math formula is broken at a
+% binary operator.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_double_hyphen_demerits_int}
+% Extra demerit charge of two (or more) lines in succession end
+% in a hyphen.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_emergency_stretch_skip}
+% Additional stretch assumed for each line if no better line breaking
+% can be found without it. This stretch is not actually added to lines,
+% so its use may result in underfull box warnings.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_final_hyphen_demerits_int}
+% Extra demerit charge if the second last line is hyphenated.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_linebreak_badness_int}
+% Boundary that if exceeded will cause \TeX{} to report an
+% underfull line.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_linebreak_fuzz_dim}
+% Boundary below which overfull lines are not reported.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_linebreak_penalty_int}
+% Extra penalty charged per line in the paragraph. By making
+% this penalty higher \TeX{} will try harder to produce compact
+% paragraphs.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_linebreak_pretolerance_int}
+% Maximum tolerance allowed for individual lines to break the
+% paragraph without attempting hyphenation.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_linebreak_tolerance_int}
+% Maximum tolerance allowed for individual lines when breaking a
+% paragraph while attempting hyphenation (if this limit can't be
+% met \cs{l_galley_emergency_stretch_skip} comes into play).
+% \end{variable}
+%
+% \begin{variable}{\l_galley_mismatch_demerits_int}
+% Extra demerit charge if two visually incompatible lines follow
+% each other.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_relation_penalty_int}
+% Penalty charged if an inline math formula is broken at a
+% relational symbol.
+% \end{variable}
+%
+% \subsection{Paragraph breaking}
+%
+% \begin{variable}{\l_galley_parbreak_badness_int}
+% Boundary that if exceeded will cause \TeX{} to report an
+% underfull vertical box.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_parbreak_fuzz_dim}
+% Boundary below which overfull vertical boxes are not reported.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_broken_penalty_int}
+% Penalty for page breaking after a hyphenated line.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_pre_display_penalty_int}
+% Penalty for breaking between immediately before display math material.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_post_display_penalty_int}
+% Penalty for breaking between immediately after display math material.
+% \end{variable}
+%
+% \begin{function}
+% {
+% \galley_set_club_penalties:n,
+% \galley_set_club_penalties:V,
+% \galley_set_club_penalties:v,
+% \galley_set_display_club_penalties:n,
+% \galley_set_display_club_penalties:V,
+% \galley_set_display_club_penalties:v,
+% \galley_set_display_widow_penalties:n,
+% \galley_set_display_widow_penalties:V,
+% \galley_set_display_widow_penalties:v,
+% \galley_set_widow_penalties:n,
+% \galley_set_widow_penalties:V,
+% \galley_set_widow_penalties:v
+% }
+% \begin{syntax}
+% \cs{galley_set_club_penalties:n} \Arg{penalty list}
+% \end{syntax}
+% Set the penalties for breaking lines at the beginning and end of
+% (partial) paragraphs. In each case, the \meta{penalty list} is a
+% comma-separated list of penalty values. The list applies as follows:
+% \begin{itemize}
+% \item[\texttt{club}] Penalties for breaking after the first, second,
+% third, \emph{etc.}~line of the paragraph.
+% \item[\texttt{display_club}] Penalties for breaking after the first,
+% second, third, \emph{etc.}~line after a display math environment.
+% \item[\texttt{display_club}] Penalties for breaking before the last,
+% penultimate, antepenultimate, \emph{etc.}~line before a display
+% math environment.
+% \item[\texttt{widow}] Penalties for breaking before the last,
+% penultimate, antepenultimate, \emph{etc.}~line of the paragraph.
+% \end{itemize}
+% In all cases, these penalties apply in addition to the general interline
+% penalty or to any \enquote{special} line penalties.
+% \end{function}
+%
+% \begin{function}{\galley_set_interline_penalty:n}
+% \begin{syntax}
+% \cs{galley_set_interline_penalty:n} \Arg{penalty}
+% \end{syntax}
+% Sets the standard interline penalty applied between lines of a paragraph.
+% This value is added to any (display) club or widow penalty in force.
+% \end{function}
+%
+% \begin{function}
+% {
+% \galley_set_interline_penalties:n,
+% \galley_set_interline_penalties:V
+% }
+% \begin{syntax}
+% \cs{galley_set_interline_penalties:n} \Arg{penalty list}
+% \end{syntax}
+% Sets \enquote{special} interline penalties to be used in place of
+% the standard value, specified as a comma-separated \meta{penalty list}.
+% The \meta{penalties} apply to the first, second, third, \emph{etc.}~line
+% of the paragraph.
+% \end{function}
+%
+% \begin{function}
+% {
+% \galley_save_club_penalties:N,
+% \galley_save_display_club_penalties:N,
+% \galley_save_display_widow_penalties:N,
+% \galley_save_interline_penalties:N,
+% \galley_save_widow_penalties:N
+% }
+% \begin{syntax}
+% \cs{galley_save_club_penalties:N} \Arg{comma list}
+% \end{syntax}
+% These functions save the current value of the appropriate to the
+% comma list specified, within the current \TeX{} group.
+% \end{function}
+%
+% \begin{function}[EXP]{\galley_interline_penalty:}
+% \begin{syntax}
+% \cs{galley_interline_penalty:}
+% \end{syntax}
+% Expands to the current interline penalty as a \meta{integer denotation}.
+% \end{function}
+%
+% \section{Hooks and insertion points}
+%
+% \begin{variable}{\g_galley_par_begin_hook_tl}
+% Token list inserted at the beginning of every paragraph in horizontal mode.
+% This is inserted after any paragraph indent but before any other horizontal
+% mode material.
+% \end{variable}
+%
+% \begin{variable}{\g_galley_par_end_hook_tl}
+% Token list inserted at the end of every paragraph in horizontal mode.
+% \end{variable}
+%
+% \begin{variable}{\g_galley_par_after_hook_tl}
+% Token list inserted after each paragraph. This is used for resetting
+% galley parameters, and is therefore cleared after use.
+% \end{variable}
+%
+% \begin{variable}{\g_galley_whatsit_next_tl}
+% Token list for whatsits to be inserted at the very beginning of the next
+% paragraph started.
+% \end{variable}
+%
+% \begin{variable}{\g_galley_whatsit_previous_hook_tl}
+% Token list for whatsits to be inserted at the very end of the last
+% paragraph started.
+% \end{variable}
+%
+% \section{Internal variables}
+%
+% Some of the internal variables for the galley mechanism may be of
+% interest to the programmer. These should all be treated as read-only
+% values and accessed only through the defined interfaces described above.
+%
+% \begin{variable}{\l_galley_total_left_margin_dim}
+% The total margin between the left side of the galley and the left side of
+% the text block. This may be negative if the measure is set to overlap
+% the text beyond the edge of the galley.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_total_right_margin_dim}
+% The total margin between the right side of the galley and the right side
+% of the text block. This may be negative if the measure is set to overlap
+% the text beyond the edge of the galley.
+% \end{variable}
+%
+% \begin{variable}{\l_galley_text_width_dim}
+% The width of a line of text within the galley, taking account of
+% any margins added. This may be larger than \cs{l_galley_width_dim}
+% if the margins are negative.
+% \end{variable}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3galley} Implementation}
+%
+% At the implementation level, there are a number of challenges which
+% have to be overcome in order to make the galley easy to use at the
+% designer and user levels. Inserting material into the main vertical
+% list is in many ways an irreversible operation. Inserting items as
+% they appear in the source is therefore not desirable. Instead,
+% inserting vertical-mode material needs to be delayed until the start
+% of the \enquote{next} paragraph. This is particularly notable for
+% invisible items such as whatsits and specials, which will otherwise
+% cause changes in spacing. Delaying insertion enables user-supplied
+% settings to override design settings in a reliable fashion. This can
+% be achieved as the design-level material can be ignored if a user
+% value is supplied. There is a need to allow proper nesting of
+% galleys, which means that all of the above needs to be set up so that
+% it can be saved and restored. All of these manipulations require
+% altering the meaning of the \cs{par} token, which is particularly
+% awkward as \TeX{} inserts a token \emph{called} \cs{par} rather than
+% one with a particular meaning. This makes moving \cs{par} to somewhere
+% \enquote{safe} extremely challenging.
+%
+% Added to all of this complexity, there is a need to deal with
+% \enquote{display-like} material. The most obvious example is the way
+% lists are handled. These use \cs{par} tokens to achieve the correct
+% appearance, but at the same time
+% \begin{verbatim}
+% Text
+% \begin{itemize}
+% \item An item
+% \end{itemize}
+% More text
+% \end{verbatim}
+% should form one visual paragraph while
+% \begin{verbatim}
+% Text
+% \begin{itemize}
+% \item An item
+% \end{itemize}
+%
+% More text
+% \end{verbatim}
+% should be shown as two paragraphs. This requires an additional level
+% of handling so that the \cs{par} token used to end the list in the
+% first case does not start a new paragraph in a visual sense while the
+% second does.
+%
+% Another factor to bear in mind is that \cs{tex_everypar:D} may be
+% executed inside a group. For example, a paragraph starting
+% \begin{verbatim}
+% {Text} here
+% \end{verbatim}
+% will insert the tokens such that the current group level is $1$
+% higher for \enquote{Text} than for \enquote{here}. The result of this
+% is that it's very important to watch how flags are set and reset. This
+% can only be done reliably on a global level, which then has a knock-on
+% effect on the rest of the implementation.
+%
+% At a \TeX{} level, settings can only apply to the current paragraph,
+% but conceptually there is a need to allow for both single-paragraph
+% and \enquote{running} settings. Whenever the code switches galley
+% level both of these need to be correctly saved.
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*package>
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\package_check_loaded_expl:
+%</package>
+% \end{macrocode}
+%
+% \subsection{Support items}
+%
+% Functions or settings which are needed by the galley but perhaps also
+% elsewhere.
+%
+% \begin{macro}{\galley_leave_vmode:}
+% The standard mode to leave vertical mode, starting a paragraph.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_leave_vmode:
+ { \tex_unhbox:D \c_empty_box }
+% \end{macrocode}
+% \end{macro}
+%
+% The default hyphenation character should be set and hyphenation should be
+% enabled.
+% \begin{macrocode}
+%<*initex>
+\tex_defaulthyphenchar:D 45 \scan_stop:
+%</initex>
+% \end{macrocode}
+%
+% \subsection{Galley settings}
+%
+% Settings for application by the galley respect the usual \TeX{} grouping and
+% so are all local variables.
+%
+% \begin{variable}
+% {
+% \l_galley_parshape_left_indent_clist,
+% \l_galley_parshape_right_indent_clist
+% }
+% \begin{variable}
+% {
+% \l_galley_parshape_multipar_bool,
+% \l_galley_parshape_resume_std_bool,
+% \l_galley_parshape_fixed_lines_bool
+% }
+% Setting up paragraph shape interacts with setting up the measure. The only
+% way to keep things flexible is to have a rather \enquote{rich} set of data
+% available.
+% \begin{macrocode}
+\clist_new:N \l_galley_parshape_left_indent_clist
+\clist_new:N \l_galley_parshape_right_indent_clist
+\bool_new:N \l_galley_parshape_multipar_bool
+\bool_new:N \l_galley_parshape_resume_std_bool
+\bool_new:N \l_galley_parshape_fixed_lines_bool
+\int_new:N \l_galley_parshape_std_lines_int
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+%
+% \begin{variable}{\l_galley_text_width_dim}
+% The width of the current measure: the \enquote{running} setting can be
+% inherited from \LaTeXe{}.
+% \begin{macrocode}
+%<*initex>
+\dim_new:N \l_galley_text_width_dim
+%</initex>
+%<*package>
+\cs_new_eq:NN \l_galley_text_width_dim \linewidth
+%</package>
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {\l_galley_total_left_margin_dim, \l_galley_total_right_margin_dim}
+% Margins of the current text within the galley: these plus the galley
+% width are one way to define the measure width. See also the text width,
+% which is an alternative view (and should be in sync with this one!).
+% \begin{macrocode}
+%<*initex>
+\dim_new:N \l_galley_total_left_margin_dim
+%</initex>
+%<*package>
+\cs_new_eq:NN \l_galley_total_left_margin_dim \@totalleftmargin
+%</package>
+\dim_new:N \l_galley_total_right_margin_dim
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {\l_galley_interpar_penalty_skip, \l_galley_interpar_vspace_skip}
+% Items between paragraphs at the design level.
+% \begin{macrocode}
+\int_new:N \l_galley_interpar_penalty_int
+\skip_new:N \l_galley_interpar_vspace_skip
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_galley_width_dim}
+% The external size of a galley is the stored in the \TeX{} primitive
+% \cs{tex_hsize:D}, which is renamed. This will only ever be reset by
+% the code constructing a new galley, for example the start of a
+% minipage. This value will be set for the main galley by the page
+% layout system.
+% \begin{macrocode}
+\cs_new_eq:NN \l_galley_width_dim \tex_hsize:D
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Galley data structures}
+%
+% In contrast to settings, the data structures used by the galley are all set
+% globally. To allow different galley levels to exist, a local variant is
+% defined for each one to save the value when starting a new level.
+%
+% \begin{variable}{\g_galley_begin_level_bool, \l_galley_begin_level_bool}
+% Indicates that the galley is at the very beginning of the level, and that
+% no material has yet been set. As a result, the global version is set
+% \texttt{true} to begin with.
+% \begin{macrocode}
+\bool_new:N \g_galley_begin_level_bool
+\bool_new:N \l_galley_begin_level_bool
+\bool_gset_true:N \g_galley_begin_level_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_galley_omit_next_indent_bool, \l_galley_omit_next_indent_bool}
+% A global flag is needed for suppressing indentation of the next
+% paragraph. This does not need a \enquote{running} version since that
+% should be handled using the \texttt{justification} object: the two
+% concepts are related but not identical. The flag here is needed in
+% cases such as the very first paragraph in a galley or immediately
+% following a heading.
+% \begin{macrocode}
+\bool_new:N \g_galley_omit_next_indent_bool
+\bool_new:N \l_galley_omit_next_indent_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_galley_parshape_set_bool, \l_galley_parshape_set_bool}
+% This is not a setting for paragraph shape, but rather a tracker for the
+% galley system.
+% \begin{macrocode}
+\bool_new:N \g_galley_parshape_set_bool
+\bool_new:N \l_galley_parshape_set_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_galley_nobreak_next_bool, \l_galley_nobreak_next_bool}
+% Dealing with the no-break flag is pretty much the same as the case
+% for the indent: this applies on a single paragraph basis.
+% \begin{macrocode}
+\bool_new:N \g_galley_nobreak_next_bool
+\bool_new:N \l_galley_nobreak_next_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \g_galley_par_begin_hook_tl, \l_galley_par_begin_hook_tl,
+% \g_galley_par_end_hook_tl, \l_galley_par_end_hook_tl,
+% }
+% Hooks for user-level code: these are not used by the galley itself.
+% \begin{macrocode}
+\tl_new:N \g_galley_par_begin_hook_tl
+\tl_new:N \l_galley_par_begin_hook_tl
+\tl_new:N \g_galley_par_end_hook_tl
+\tl_new:N \l_galley_par_end_hook_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {\g_galley_par_after_hook_tl, \l_galley_par_after_hook_tl}
+% This one is used by the galley: it happens \enquote{after} the current
+% paragraph, and is used for reset purposes.
+% \begin{macrocode}
+\tl_new:N \g_galley_par_after_hook_tl
+\tl_new:N \l_galley_par_after_hook_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {\g_galley_previous_par_lines_int, \l_galley_previous_par_lines_int}
+% The number of lines in the previous typeset paragraph. This is reset at
+% the start of the paragraph and \emph{added to} when each \cs{tex_par:D}
+% primitive is used: \LaTeX{} uses the primitive in places that do not end
+% a (conceptual) paragraph.
+% \begin{macrocode}
+\int_new:N \g_galley_previous_par_lines_int
+\int_new:N \l_galley_previous_par_lines_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_galley_restore_running_tl, \l_galley_restore_running_tl}
+% When a parameter is altered from the \enquote{running} value to a
+% different \enquote{current} one, there needs to be a method to restore
+% the \enquote{running} value. This is done by adding the necessary
+% assignment to a token list, which can be executed when needed. At the
+% same time, this information is itself part of the galley parameter
+% structure, and so there has to be a local save version.
+% \begin{macrocode}
+\tl_new:N \g_galley_restore_running_tl
+\tl_new:N \l_galley_restore_running_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \g_galley_whatsit_next_tl, \l_galley_whatsit_next_tl,
+% \g_galley_whatsit_previous_tl, \l_galley_whatsit_previous_tl
+% }
+% Whatsits only apply on a per-paragraph basis and so there is no need
+% to differentiate between current and running values. However, there
+% is a need to differentiate between whatsits that attach to the
+% previous (completed) paragraph and those that attach to the next
+% paragraph.
+% \begin{macrocode}
+\tl_new:N \g_galley_whatsit_next_tl
+\tl_new:N \l_galley_whatsit_next_tl
+\tl_new:N \g_galley_whatsit_previous_tl
+\tl_new:N \l_galley_whatsit_previous_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {\g_galley_interpar_penalty_user_tl, \l_galley_interpar_penalty_user_tl}
+% The user may want to over-ride the penalty for a break between
+% paragraphs, for example to prevent a break when the overall design
+% allows one. This is handled using an additional penalty.
+% \begin{macrocode}
+\tl_new:N \g_galley_interpar_penalty_user_tl
+\tl_new:N \l_galley_interpar_penalty_user_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {\g_galley_interpar_vspace_user_tl, \l_galley_interpar_vspace_user_tl}
+% Arbitrary vertical space can be inserted by the user on a one-off
+% basis. This is used in place of any running space between paragraphs.
+% \begin{macrocode}
+\tl_new:N \g_galley_interpar_vspace_user_tl
+\tl_new:N \l_galley_interpar_vspace_user_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Independent galley levels}
+%
+% As well as the main vertical list, independent galleys are required
+% for items such as minipages and marginal notes. Each of these galleys
+% requires an independent set of global data structures. This is
+% achieved by storing the data structures in \emph{local} variables. The
+% later are only used to save and restore the global value, and so \TeX{}
+% grouping will manage the values correctly. This implies that each
+% galley level must form a group: galley levels are tided to vertical
+% boxes and so this is a reasonable requirements.
+%
+% \begin{macro}{\galley_initialise_variables:}
+% At the start of a galley level, both the global and local variables
+% will need to be reset to standard values. For example, the measure
+% is set to the galley width and any paragraph shape is cleared.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_initialise_variables:
+ {
+ \bool_gset_true:N \g_galley_begin_level_bool
+ \tl_gclear:N \g_galley_interpar_penalty_user_tl
+ \tl_gclear:N \g_galley_interpar_vspace_user_tl
+ \bool_gset_true:N \g_galley_omit_next_indent_bool
+ \bool_gset_false:N \g_galley_nobreak_next_bool
+ \tl_gclear:N \g_galley_par_begin_hook_tl
+ \tl_gclear:N \g_galley_par_end_hook_tl
+ \tl_gclear:N \g_galley_par_after_hook_tl
+ \bool_gset_false:N \g_galley_parshape_set_bool
+ \int_gzero:N \g_galley_previous_par_lines_int
+ \tl_gclear:N \g_galley_restore_running_tl
+ \tl_gclear:N \g_galley_whatsits_previous_tl
+ \tl_gclear:N \g_galley_whatsits_next_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\galley_initialise_settings:}
+% This sets the local values of the various galley settings.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_initialise_settings:
+ {
+ \dim_set_eq:NN \l_galley_text_width_dim \l_galley_width_dim
+ \dim_zero:N \l_galley_left_margin_dim
+ \dim_zero:N \l_galley_right_margin_dim
+ \dim_zero:N \l_galley_total_left_margin_dim
+ \dim_zero:N \l_galley_total_right_margin_dim
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\galley_save_parameters:, \galley_restore_parameters:}
+% Saving and restoring parameters is carried out by a series of copy
+% functions.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_save_parameters:
+ {
+ \bool_set_eq:NN \l_galley_begin_level_bool
+ \g_galley_begin_level_bool
+ \tl_set_eq:NN \l_galley_interpar_penalty_user_tl
+ \g_galley_interpar_penalty_user_tl
+ \tl_set_eq:NN \l_galley_interpar_vspace_user_tl
+ \g_galley_interpar_vspace_user_tl
+ \bool_set_eq:NN \l_galley_omit_next_indent_bool
+ \g_galley_omit_next_indent_bool
+ \bool_set_eq:NN \l_galley_nobreak_next_bool
+ \g_galley_nobreak_next_bool
+ \tl_set_eq:NN \l_galley_par_begin_hook_tl
+ \g_galley_par_begin_hook_tl
+ \tl_set_eq:NN \l_galley_par_end_hook_tl
+ \g_galley_par_end_hook_tl
+ \tl_set_eq:NN \l_galley_par_after_hook_tl
+ \g_galley_par_after_hook_tl
+ \bool_set_eq:NN \l_galley_parshape_set_bool
+ \g_galley_parshape_set_bool
+ \int_set_eq:NN \l_galley_previous_par_lines_int
+ \g_galley_previous_par_lines_int
+ \tl_set_eq:NN \l_galley_restore_running_tl
+ \g_galley_restore_running_tl
+ \tl_set_eq:NN \l_galley_whatsits_previous_tl
+ \g_galley_whatsits_previous_tl
+ \tl_set_eq:NN \l_galley_whatsits_next_tl
+ \g_galley_whatsits_next_tl
+ }
+\cs_new_protected_nopar:Npn \galley_restore_parameters:
+ {
+ \bool_gset_eq:NN \g_galley_begin_level_bool
+ \l_galley_begin_level_bool
+ \tl_gset_eq:NN \g_galley_interpar_penalty_user_tl
+ \l_galley_interpar_penalty_user_tl
+ \tl_gset_eq:NN \g_galley_interpar_vspace_user_tl
+ \l_galley_interpar_vspace_user_tl
+ \bool_gset_eq:NN \g_galley_omit_next_indent_bool
+ \l_galley_omit_next_indent_bool
+ \bool_gset_eq:NN \g_galley_nobreak_next_bool
+ \l_galley_nobreak_next_bool
+ \tl_gset_eq:NN \g_galley_par_begin_hook_tl
+ \l_galley_par_begin_hook_tl
+ \tl_gset_eq:NN \g_galley_par_end_hook_tl
+ \l_galley_par_end_hook_tl
+ \tl_gset_eq:NN \g_galley_par_after_hook_tl
+ \l_galley_par_after_hook_tl
+ \bool_gset_eq:NN \g_galley_parshape_set_bool
+ \l_galley_parshape_set_bool
+ \int_gset_eq:NN \g_galley_previous_par_lines_int
+ \l_galley_previous_par_lines_int
+ \tl_gset_eq:NN \g_galley_restore_running_tl
+ \l_galley_restore_running_tl
+ \tl_gset_eq:NN \g_galley_whatsits_previous_tl
+ \l_galley_whatsits_previous_tl
+ \tl_gset_eq:NN \g_galley_whatsits_next_tl
+ \l_galley_whatsits_next_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\galley_level:}
+% \begin{macro}[aux]{\galley_level_end:}
+% Galley levels are created by saving all of the current global
+% settings, starting a group then initialising both the local and global
+% variables.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_level:
+ {
+ \galley_save_parameters:
+ \group_begin:
+ \galley_initialise_variables:
+ \galley_initialise_settings:
+ \group_insert_after:N \galley_level_end:
+ }
+% \end{macrocode}
+% At the end of the level, the global values are restored using the
+% saved \emph{local} versions, hence the position of the close-of-group
+% instruction. As this code can be inserted automatically, at the point
+% of use only the start of a galley level needs to be marked up: the end
+% must come in a fixed location. All of this relies on the the
+% \enquote{colour safe} group used inside a box.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_level_end:
+ {
+ \par
+ \galley_restore_parameters:
+ \group_end:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{The \cs{par} token}
+%
+% \begin{macro}{\galley_std_par:}
+% In vertical mode, the standard paragraph insert is just the primitive
+% \cs{tex_par:D}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_std_par:
+ {
+ \mode_if_vertical:TF
+ { \tex_par:D }
+% \end{macrocode}
+% In horizontal mode, the paragraph shape is set \enquote{just in time}
+% before inserting \cs{tex_par:D}. The \cs{tex_par:D} is inside a
+% group to preserve some dynamic settings (for example
+% \cs{etex_interlinepenalties}). Once the
+% paragraph has been typeset, the number of lines is \emph{added} to the
+% running total. It's possible that the conceptual paragraph contains
+% display-like material, and simply setting the number of lines equal to
+% \cs{tex_prevgraf:D} would \enquote{loose} these.
+% \begin{macrocode}
+ {
+ \g_galley_par_end_hook_tl
+ \galley_set_measure_and_parshape:
+ \group_begin:
+ \tex_par:D
+ \group_end:
+ \int_gadd:Nn \g_galley_previous_par_lines_int \tex_prevgraf:D
+ }
+ \g_galley_par_after_hook_tl
+ \tl_gclear:N \g_galley_par_after_hook_tl
+% \end{macrocode}
+% The non-breaking penalty is needed here as within the \cs{tex_everypar:D}
+% hook there is an additional \cs{tex_par:D}. This leads to an extra
+% \cs{tex_parskip:D}, which will leave an unwanted break-point here
+% otherwise.
+% \begin{macrocode}
+ \tex_penalty:D \c_ten_thousand
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\par}
+% The meaning of the token \cs{par} itself starts off as a standard
+% paragraph.
+% \begin{macrocode}
+\cs_set_protected_nopar:Npn \par { \galley_std_par: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@par}
+% \LaTeXe{} requires a \enquote{long term} version of \cs{par}, which is
+% stored as \cs{@par}. Things are done a bit differently by \LaTeX3 and
+% so this will only be needed in package mode.
+% \begin{macrocode}
+%<*package>
+\tl_set:Nn \@par { \galley_std_par: }
+%</package>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Display levels}
+%
+% \begin{macro}{\galley_display_begin:, \galley_display_end:}
+% \begin{macro}[aux]{\galley_display_penalty:N, \galley_display_vspace:N}
+% \begin{macro}[aux]{\galley_display_par_setup:, \galley_display_par:}
+% Display items within the galley are a bit like galley levels: they
+% may have different paragraph settings to the main part of the galley.
+% On the other hand, unlike independent galleys they should inherit the
+% settings from the surrounding material. They may also start and end with
+% special spacing values.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_display_begin:
+ {
+ \group_begin:
+ \galley_save_parameters:
+ \mode_if_vertical:TF
+ {
+ \galley_display_penalty:N \l_galley_display_begin_par_penalty_tl
+ \galley_display_vspace:N \l_galley_display_begin_par_vspace_tl
+ }
+ {
+ \galley_display_penalty:N \l_galley_display_begin_penalty_tl
+ \galley_display_vspace:N \l_galley_display_begin_vspace_tl
+ }
+ \par
+ }
+% \end{macrocode}
+% Two short-cuts for setting up any special penalty or vertical space.
+% The idea is that the standard value is saved to the \enquote{restore}
+% token list, before setting up the value to the special value needed
+% in this one case.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_display_penalty:N #1
+ {
+ \tl_if_empty:NF #1
+ {
+ \tl_gput_right:Nx \g_galley_restore_running_tl
+ {
+ \int_gset:Nn \exp_not:N \g_galley_penalty_int
+ { \int_use:N \g_galley_penalty_int }
+ }
+ \int_gset:Nn \g_galley_penalty_int {#1}
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_display_vspace:N #1
+ {
+ \tl_if_empty:NF #1
+ {
+ \tl_gput_right:Nx \g_galley_restore_running_tl
+ {
+ \skip_gset:Nn \exp_not:N \g_galley_vspace_skip
+ { \skip_use:N \g_galley_vspace_skip }
+ }
+ \skip_gset:Nn \g_galley_vspace_int {#1}
+ }
+ }
+% \end{macrocode}
+% The \cs{par} token at the end of the display needs to go in at the same
+% group level as the text, hence this function cannot be placed using
+% \cs{group_insert_after:N}. Resetting the meaning of the \cs{par} token
+% needs to be carried out after the group used for the environment.
+% As \LaTeXe{} already adds one group, there are two \enquote{escapes}
+% here: the format version needs only one escape.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_display_end:
+ {
+ \par
+ \galley_restore_parameters:
+ \group_end:
+%<*package>
+ \group_insert_after:N \group_insert_after:N
+%</package>
+ \group_insert_after:N \galley_display_par_setup:
+ }
+% \end{macrocode}
+% The method used here is to assume that the next piece of horizontal
+% mode material will follow on from the displayed output without an
+% intervening \cs{par} token (probably a blank line). The meaning of the
+% \cs{par} token is then altered so that a check can be made to see if
+% this assumption was correct.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_display_par_setup:
+ {
+ \bool_gset_false:N \g_galley_omit_next_indent_bool
+ \cs_set_eq:NN \par \galley_display_par:
+ }
+% \end{macrocode}
+% The \enquote{special} meaning of the paragraph token starts by putting
+% things back to normal: there should never need to be more than one
+% special paragraph marker in one group. If \TeX{} is in vertical mode,
+% then there has been a paragraph token inserted, most likely by a
+% blank line. Thus the next piece of material is a separate conceptual
+% paragraph from the display. In that case, the assumption from above is
+% undone and the indent is turned back on. On the other hand, for the
+% case where \TeX{} is in horizontal mode then a \cs{tex_par:D} primitive
+% is required in the same way as in \cs{galley_standard_par:}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_display_par:
+ {
+ \cs_set_eq:NN \par \galley_std_par:
+ \mode_if_vertical:TF
+ {
+ \par
+ \bool_gset_false:N \g_galley_omit_next_indent_bool
+ \galley_display_penalty:N \l_galley_display_end_par_penalty_tl
+ \galley_display_vspace:N \l_galley_display_end_par_vspace_tl
+ }
+ {
+ \galley_set_measure_and_parshape:
+ \group_begin:
+ \tex_par:D
+ \group_end:
+ \int_gadd:Nn \g_galley_previous_par_lines_int \tex_prevgraf:D
+ \galley_display_penalty:N \l_galley_display_end_penalty_tl
+ \galley_display_vspace:N \l_galley_display_end_vspace_tl
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Insertions using \cs{tex_everypar:D}}
+%
+% The key to the entire galley mechanism is hooking into the
+% \cs{tex_everypar:D} token register. This requires that the original
+% is moved out of the way, with appropriate hooks left attached for
+% further modification by other modules and by the user. This is all
+% done such that there is no danger of accidentally deactivating the
+% galley mechanism.
+%
+% \begin{macro}{\everypar}
+% When used on top of \LaTeXe{} the original primitive name needs to be
+% available without the risk of completely overwriting the new
+% mechanism. This is implemented as a token register in case low-level
+% \TeX{} is used. The \TeX{} primitive is set here as otherwise the
+% \LaTeXe{} \cs{@nodocument} is never removed from the register.
+% This precaution is not be needed for a stand-alone format.
+% \begin{macrocode}
+%<*initex>
+\tex_everypar:D % TEMP
+ {
+ \bool_if:NTF \g_galley_begin_level_bool
+ { \galley_start_paragraph_first: }
+ { \galley_start_paragraph_std: }
+ }
+%</initex>
+%<*package>
+\cs_undefine:N \everypar
+\newtoks \everypar
+\AtBeginDocument
+ {
+ \tex_everypar:D
+ {
+ \bool_if:NTF \g_galley_begin_level_bool
+ { \galley_start_paragraph_first: }
+ { \galley_start_paragraph_std: }
+ \tex_the:D \everypar
+ }
+ }
+%</package>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{The galley mechanism}
+%
+% \begin{variable}{\g_galley_last_box}
+% A temporary box to hold the box inserted by \TeX{} when a paragraph
+% is inserted with an indent. The galley actually inserts the space
+% (\emph{i.e.}~\cs{tex_parindent:D} is globally zero), but there is
+% still an empty box to test for.
+% \begin{macrocode}
+\box_new:N \g_galley_last_box
+% \end{macrocode}
+% \end{variable}
+%
+% The \enquote{start of paragraph} routines are fired by \cs{tex_everypar:D}.
+% This can take place within a group in a construction such as
+% \begin{verbatim}
+% ... end of last par.
+%
+% {\Large Start} of par
+% \end{verbatim}
+% and so anything applied here must be done globally.
+%
+% \begin{macro}[int]{\galley_start_paragraph_std:}
+% The routine at the start of a paragraph starts by removing any
+% (empty) indent box from the vertical list. As there may be vertical
+% mode items still to insert, a \cs{tex_par:D} primitive is used to
+% get back into vertical mode before they are tidied up. To get back
+% again to horizontal mode, \cs{tex_noindent:D} can be used. To avoid
+% an infinite loop, \cs{tex_everypar:D} is locally cleared before doing
+% that. Back in horizontal mode, the horizontal mode items can be
+% tidied up before sorting out any items which have been set on a
+% single-paragraph basis.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_start_paragraph_std:
+ {
+ \group_begin:
+ \box_gset_to_last:N \g_galley_last_box
+ \tex_par:D
+ \galley_insert_vertical_items:
+ \tex_everypar:D { }
+ \tex_noindent:D
+ \group_end:
+ \int_gzero:N \g_galley_previous_par_lines_int
+ \galley_insert_horizontal_items:
+ \galley_restore_running_parameters:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\galley_start_paragraph_first:}
+% For the very first paragraph in a galley, the code needs to avoid
+% adding any unnecessary vertical items at the top as it will interfere with
+% vertical positioning in \cs{tex_vtop:D}.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_start_paragraph_first:
+ {
+ \bool_gset_false:N \g_galley_begin_level_bool
+ \mode_if_horizontal:TF
+ {
+ \group_begin:
+ \box_gset_to_last:N \g_galley_last_box
+ \tex_par:D
+ \galley_insert_vspace:
+ \tex_everypar:D { }
+ \tex_noindent:D
+ \group_end:
+ }
+ { \galley_insert_vspace: }
+ \galley_insert_horizontal_items:
+ \galley_restore_running_parameters:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\galley_insert_vertical_items, \galley_insert_vspace:}
+% The aim here is to insert the vertical items such that they attach to
+% the correct place. This function is used as part of the \cs{tex_everypar:D}
+% mechanism, meaning that the immediately-preceding item on the vertical
+% list is the \cs{tex_parskip:D}, always zero-length but an implicit
+% penalty. So any whatsits \enquote{attached} to the previous paragraph
+% should stay glued on. After the whatsits, a penalty for
+% breaking will be inserted. This will be the user penalty if supplied,
+% or the running penalty unless the no-break flag is set. Finally,
+% the inter-paragraph space is applied.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_insert_vertical_items:
+ {
+ \g_galley_whatsit_previous_tl
+ \tl_gclear:N \g_galley_whatsit_previous_tl
+ \tl_if_empty:NTF \g_galley_interpar_penalty_user_tl
+ {
+ \bool_if:NTF \g_galley_nobreak_next_bool
+ { \tex_penalty:D \c_ten_thousand }
+ { \tex_penalty:D \l_galley_interpar_penalty_int }
+ }
+ {
+ \tex_penalty:D
+ \int_eval:w \g_galley_interpar_penalty_user_tl \int_eval_end:
+ \tl_gclear:N \g_galley_interpar_penalty_user_tl
+ }
+ \bool_gset_false:N \g_galley_nobreak_next_bool
+ \galley_insert_vspace:
+ }
+% \end{macrocode}
+% Inserting vertical space is set up as a separate function as it comes
+% up in a few places. The idea here is that any user-set space will
+% override the design value, and only one space is ever inserted.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_insert_vspace:
+ {
+ \tl_if_empty:NTF \g_galley_interpar_vspace_user_tl
+ { \skip_vertical:N \l_galley_interpar_vspace_skip }
+ {
+ \skip_vertical:n { \g_galley_interpar_vspace_user_tl }
+ \tl_gclear:N \g_galley_interpar_vspace_user_tl
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\galley_insert_horizontal_items:}
+% Horizontal mode objects start with the whatsits for the next paragraph. An
+% indent is then included if the removed box was not void.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_insert_horizontal_items:
+ {
+ \g_galley_whatsit_next_tl
+ \tl_gclear:N \g_galley_whatsit_next_tl
+ \bool_if:NT \g_galley_omit_next_indent_bool
+ {
+ \box_if_empty:NF \g_galley_last_box
+ { \hbox_to_wd:nn \l_galley_par_indent_dim { } }
+ }
+ \skip_horizontal:N \l_galley_par_begin_skip
+ \g_galley_par_begin_hook_tl
+ \bool_gset_true:N \g_galley_omit_next_indent_bool
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\galley_restore_running_parameters:}
+% Restoring the ongoing parameters just means using the token list
+% variable in which the appropriate assignments are stored. The
+% list can then be cleared.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_restore_running_parameters:
+ {
+ \g_galley_restore_running_tl
+ \tl_gclear:N \g_galley_restore_running_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Measure}
+%
+% \begin{macro}
+% {\galley_margins_set_absolute:nn, \galley_margins_set_relative:nn}
+% Setting the measure is just a question of adjusting margins, either
+% in a relative or absolute sense.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_margins_set_absolute:nn #1#2
+ {
+ \dim_set:Nn \l_galley_total_left_margin_dim {#1}
+ \dim_set:Nn \l_galley_total_right_margin_dim {#2}
+ \dim_set:Nn \l_galley_text_width_dim
+ {
+ \l_galley_width_dim
+ - \l_galley_total_left_margin_dim
+ - \l_galley_total_right_margin_dim
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_margins_set_relative:nn #1#2
+ {
+ \dim_add:Nn \l_galley_total_left_margin_dim {#1}
+ \dim_add:Nn \l_galley_total_right_margin_dim {#2}
+ \dim_set:Nn \l_galley_text_width_dim
+ {
+ \l_galley_width_dim
+ - \l_galley_total_left_margin_dim
+ - \l_galley_total_right_margin_dim
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Paragraph shape}
+%
+% \begin{macro}
+% {
+% \galley_parshape_fixed_lines:nnn,
+% \galley_parshape_fixed_lines:nVV,
+% \galley_parshape_multi_par:nnnN,
+% \galley_parshape_multi_par:nVVN,
+% \galley_parshape_single_par:nnnN,
+% \galley_parshape_single_par:nVVN
+% }
+% Setting the paragraph shape is easy as most of the real work is done
+% later. So this is just a case of saving the various pieces of data
+% to the correct locations.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_parshape_fixed_lines:nnn #1#2#3
+ {
+ \bool_gset_true:N \g_galley_parshape_set_bool
+ \bool_set_true:N \l_galley_parshape_fixed_lines_bool
+ \int_set:Nn \l_galley_parshape_std_lines_int {#1}
+ \clist_set:Nn \l_galley_parshape_left_indent_clist {#2}
+ \clist_set:Nn \l_galley_parshape_right_indent_clist {#3}
+ \bool_set_true:N \l_galley_parshape_resume_std_bool
+ }
+\cs_new_protected_nopar:Npn \galley_parshape_multi_par:nnnN #1#2#3#4
+ {
+ \bool_gset_true:N \g_galley_parshape_set_bool
+ \bool_set_true:N \l_galley_parshape_multipar_bool
+ \bool_set_false:N \l_galley_parshape_fixed_lines_bool
+ \int_set:Nn \l_galley_parshape_std_lines_int {#1}
+ \clist_set:Nn \l_galley_parshape_left_indent_clist {#2}
+ \clist_set:Nn \l_galley_parshape_right_indent_clist {#3}
+ \bool_set_eq:NN \l_galley_parshape_resume_std_bool #4
+ }
+\cs_new_protected_nopar:Npn \galley_parshape_single_par:nnnN #1#2#3#4
+ {
+ \bool_gset_true:N \g_galley_parshape_set_bool
+ \bool_set_false:N \l_galley_parshape_multipar_bool
+ \bool_set_false:N \l_galley_parshape_fixed_lines_bool
+ \int_set:Nn \l_galley_parshape_std_lines_int {#1}
+ \clist_set:Nn \l_galley_parshape_left_indent_clist {#2}
+ \clist_set:Nn \l_galley_parshape_right_indent_clist {#3}
+ \bool_set_eq:NN \l_galley_parshape_resume_std_bool #4
+ }
+\cs_generate_variant:Nn \galley_parshape_fixed_lines:nnn { nVV }
+\cs_generate_variant:Nn \galley_parshape_multi_par:nnnN { nVV }
+\cs_generate_variant:Nn \galley_parshape_single_par:nnnN { nVV }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\galley_set_measure_and_parshape:}
+% To set the paragraph shape for the current paragraph, there is a check to
+% see if the measure alone should be used. If not, then the shape may be
+% built by paragraph or based on the number of lines required.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_set_measure_and_parshape:
+ {
+ \bool_if:NTF \g_galley_parshape_set_bool
+ {
+ \bool_if:NTF \l_galley_parshape_fixed_lines_bool
+ {
+ \int_compare:nNnTF \g_galley_previous_par_lines_int > \c_zero
+ { \galley_generate_parshape_lines: }
+ { \galley_generate_parshape: }
+ }
+ {
+ \bool_gset_eq:NN \g_galley_parshape_set_bool
+ \l_galley_parshape_multipar_bool
+ \galley_generate_parshape:
+ }
+ }
+ {
+ \tex_global:D \tex_parshape:D
+ \c_one
+ \dim_use:N \l_galley_total_left_margin_dim
+ \c_space_tl
+ \dim_use:N \l_galley_text_width_dim
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\galley_generate_parshape:}
+% \begin{macro}[aux]{\galley_set_parshape_map:nn, \galley_set_parshape_map:oo}
+% \begin{macro}[aux]{\galley_set_parshape_map_aux:nw}
+% For a shape to apply on a paragraph basis, the two user-supplied comma
+% lists are taken and converted into left-side offsets and line lengths.
+% This is all dependent on the current measure.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_generate_parshape:
+ {
+ \tex_global:D \tex_parshape:D
+ \int_eval:w
+ \l_galley_parshape_std_lines_int +
+ \int_min:nn
+ { \clist_length:N \l_galley_parshape_left_indent_clist }
+ { \clist_length:N \l_galley_parshape_right_indent_clist }
+ \bool_if:NT \l_galley_parshape_resume_std_bool { + 1 }
+ \int_eval_end:
+ \prg_replicate:nn \l_galley_parshape_std_lines_int
+ {
+ \dim_use:N \l_galley_total_left_margin_dim
+ \c_space_tl
+ \dim_use:N \l_galley_text_width_dim
+ \c_space_tl
+ }
+ \galley_set_parshape_map:oo
+ \l_galley_parshape_left_indent_clist
+ \l_galley_parshape_right_indent_clist
+ \bool_if:NT \l_galley_parshape_resume_std_bool
+ {
+ \c_space_tl
+ \dim_use:N \l_galley_total_left_margin_dim
+ \c_space_tl
+ \dim_use:N \l_galley_text_width_dim
+ }
+ }
+\cs_new_nopar:Npn \galley_set_parshape_map:nn #1#2
+ { \galley_set_parshape_map_aux:nw { } #1 , \q_mark #2 , \q_stop }
+\cs_generate_variant:Nn \galley_set_parshape_map:nn { oo }
+\cs_new_nopar:Npn \galley_set_parshape_map_aux:nw
+ #1#2 , #3 \q_mark #4 , #5 \q_stop
+ {
+ \bool_if:nTF { \tl_if_empty_p:n {#3} || \tl_if_empty_p:n {#4} }
+ {
+ #1
+ \dim_eval:n { \l_galley_total_left_margin_dim + ( #2 ) }
+ \c_space_tl
+ \dim_eval:n { \l_galley_text_width_dim - ( ( #2 ) + ( #4 ) ) }
+ }
+ {
+ \galley_set_parshape_map_aux:nw
+ {
+ #1
+ \dim_eval:n { \l_galley_total_left_margin_dim + ( #2 ) }
+ \c_space_tl
+ \dim_eval:n { \l_galley_text_width_dim - ( ( #2 ) + ( #4 ) ) }
+ \c_space_tl
+ }
+ #3 \q_mark #5 \q_stop
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\galley_generate_parshape_lines:}
+% \begin{macro}[aux]{\galley_generate_parshape_lines_aux:n}
+% The idea here is to construct a paragraph shape based on the remaining
+% lines from the shape in the previous paragraph. If the previous paragraph
+% was sufficiently long, then life is \enquote{back to normal} and the
+% standard shape is set. If a special shape is needed, this is recovered
+% from the paragraph shape using the \eTeX{} primitives.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_generate_parshape_lines:
+ {
+ \int_compare:nNnTF \tex_parshape:D > \g_galley_previous_par_lines_int
+ {
+ \tex_global:D \tex_parshape:D
+ \int_eval:w \tex_parshape:D - \g_galley_previous_par_lines_int
+ \int_eval_end:
+ \prg_stepwise_function:nnnN
+ { \g_galley_previous_par_lines_int + \c_one }
+ \c_one \tex_parshape:D \galley_generate_parshape_lines_aux:n
+ }
+ {
+ \bool_gset_false:N \g_galley_parshape_set_bool
+ \tex_global:D \tex_parshape:D
+ \c_one
+ \dim_use:N \l_galley_total_left_margin_dim
+ \c_space_tl
+ \dim_use:N \l_galley_text_width_dim
+ }
+ }
+\cs_new_nopar:Npn \galley_generate_parshape_lines_aux:n #1
+ {
+ \etex_parshapeindent:D #1
+ ~
+ \etex_parshapelength:D #1
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Between paragraphs}
+%
+% \begin{macro}{\galley_set_user_penalty:n, \galley_set_user_vspace:n}
+% User supplied penalties and spaces only apply for a single paragraph.
+% In both cases, the input values need to be checked for the correct
+% form but are stored as token lists. The \texttt{x}-type expansion
+% deals with this nicely.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_set_user_penalty:n #1
+ { \tl_gset:Nx \g_galley_interpar_penalty_user_tl { \int_eval:n {#1} } }
+\cs_new_protected_nopar:Npn \galley_set_user_vspace:n #1
+ { \tl_gset:Nx \g_galley_interpar_vspace_user_tl { \skip_eval:n {#1} } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\parskip}
+% For the package, the \cs{parskip} primitive is moved out of the
+% way as the code above is handling things.
+% \begin{macrocode}
+%<*package>
+\dim_set:Nn \parskip \c_zero_dim
+\cs_undefine:N \parskip
+\skip_new:N \parskip
+%</package>
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Formatting inside the paragraph}
+%
+% Justification is more complex than is necessarily desirable as the various
+% \TeX{} parameters here interact in ways which mean that clear separation
+% between different areas is not so easy.
+%
+% \begin{variable}
+% {
+% \l_galley_line_left_skip,
+% \l_galley_line_right_skip,
+% \l_galley_par_begin_skip,
+% \l_galley_par_end_skip,
+% \l_galley_par_indent_dim
+% }
+% The variables for setting paragraph shape: essentially, these are
+% the \TeX{} set.
+% \begin{macrocode}
+\cs_new_eq:NN \l_galley_line_left_skip \tex_leftskip:D
+\cs_new_eq:NN \l_galley_line_right_skip \tex_rightskip:D
+\dim_new:N \l_galley_par_begin_skip
+\cs_new_eq:NN \l_galley_par_end_skip \tex_parfillskip:D
+\cs_new_eq:NN \l_galley_par_indent_dim \tex_parindent:D
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_galley_last_line_fit_int}
+% One from \eTeX{}.
+% \begin{macrocode}
+\cs_new_eq:NN \l_galley_last_line_fit_int \etex_lastlinefit:D
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Inter-word spacing}
+%
+% Setting the spacing between words and between sentences is important
+% for achieving the correct output from ragged and centred output. At
+% the same time, as far as possible the aim is to retain the spacing
+% specified by the font designer and not to use arbitrary values
+% (\emph{cf.}~the approach in \emph{The \TeX{}book}, p.~101).
+%
+% \begin{macro}{\galley_set_interword_spacing:N}
+% The approach taken to setting a fixed space is to use the information
+% from the current font to set the spacing. This means that only
+% \cs{tex_spacefactor:D} needs to be set, while \cs{tex_xspacefactor:D}
+% is left alone. However, this is only necessary for fonts which have
+% a stretch component to the inter-word spacing in the first place,
+% \emph{i.e.}~monospaced fonts require no changes. The code therefore
+% checks whether there is any stretch, and if there is uses the fixed
+% component to set \cs{tex_spaceskip:D}. If there is a stretch component
+% (non-zero \cs{tex_fontdimen:D} \texttt{3}), then the \cs{teX_spaceskip:D}
+% is set to the fixed component from the font.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_set_interword_spacing:N #1
+ {
+ \bool_if:NTF #1
+ { % TODO Hook for font changes required!
+ \dim_compare:nNnTF { \tex_fontdimen:D \c_three \tex_font:D }
+ = \c_zero_dim
+ { \tex_spaceskip:D \c_zero_dim }
+ { \tex_spaceskip:D \tex_fontdimen:D \c_two \tex_font:D }
+ }
+ { \tex_spaceskip:D \c_zero_dim }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Hyphenation}
+%
+% \subsection{Line breaking}
+%
+% \begin{variable}
+% {
+% \l_galley_binop_penalty_int,
+% \l_galley_double_hyphen_demerits_int,
+% \l_galley_emergency_stretch_skip,
+% \l_galley_final_hyphen_demerits_int,
+% \l_galley_linebreak_badness_int,
+% \l_galley_linebreak_fuzz_dim,
+% \l_galley_linebreak_penalty_int,
+% \l_galley_linebreak_pretolerance_int,
+% \l_galley_linebreak_tolerance_int,
+% \l_galley_mismatch_demerits_int,
+% \l_galley_relation_penalty_int
+% }
+% All \TeX{} primitives renamed.
+% \begin{macrocode}
+\cs_new_eq:NN \l_galley_binop_penalty_int \tex_binoppenalty:D
+\cs_new_eq:NN \l_galley_double_hyphen_demerits_int \tex_doublehyphendemerits:D
+\cs_new_eq:NN \l_galley_emergency_stretch_skip \tex_emergencystretch:D
+\cs_new_eq:NN \l_galley_final_hyphen_demerits_int \tex_finalhyphendemerits:D
+\cs_new_eq:NN \l_galley_linebreak_badness_int \tex_hbadness:D
+\cs_new_eq:NN \l_galley_linebreak_fuzz_dim \tex_hfuzz:D
+\cs_new_eq:NN \l_galley_linebreak_penalty_int \tex_linepenalty:D
+\cs_new_eq:NN \l_galley_linebreak_pretolerance_int \tex_pretolerance:D
+\cs_new_eq:NN \l_galley_mismatch_demerits_int \tex_adjdemerits:D
+\cs_new_eq:NN \l_galley_relation_penalty_int \tex_relpenalty:D
+\cs_new_eq:NN \l_galley_linebreak_tolerance_int \tex_tolerance:D
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Paragraph breaking}
+%
+% \begin{variable}
+% {
+% \l_galley_broken_penalty_int,
+% \l_galley_interline_penalty_int,
+% \l_galley_parbreak_badness_int,
+% \l_galley_parbreak_fuzz_dim,
+% \l_galley_post_display_penalty_int,
+% \l_galley_pre_display_penalty_int
+%
+% }
+% \TeX{} primitives renamed cover \emph{some} of this.
+% \begin{macrocode}
+\cs_new_eq:NN \l_galley_broken_penalty_int \tex_brokenpenalty:D
+\cs_new_eq:NN \l_galley_interline_penalty_int \tex_interlinepenalty:D
+\cs_new_eq:NN \l_galley_parbreak_badness_int \tex_vbadness:D
+\cs_new_eq:NN \l_galley_parbreak_fuzz_dim \tex_vfuzz:D
+\cs_new_eq:NN \l_galley_post_display_penalty_int \tex_postdisplaypenalty:D
+\cs_new_eq:NN \l_galley_pre_display_penalty_int \tex_predisplaypenalty:D
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\l_galley_club_penalties_clist, \l_galley_line_penalties_clist}
+% These are used to keep a track of information which cannot be
+% extracted out of the primitives due to the overlapping nature of
+% the meanings.
+% \begin{macrocode}
+\clist_new:N \l_galley_club_penalties_clist
+\clist_new:N \l_galley_line_penalties_clist
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \galley_set_display_widow_penalties:n,
+% \galley_set_display_widow_penalties:V,
+% \galley_set_display_widow_penalties:v,
+% \galley_set_widow_penalties:n,
+% \galley_set_widow_penalties:V,
+% \galley_set_widow_penalties:v
+% }
+% \begin{macro}[aux]{\galley_set_aux:n}
+% By far the easiest penalties to deal with are those for widows. These
+% work exactly as the names imply, with the display version only used
+% immediately before display math, and the standard penalty used at the end
+% of a paragraph. Thus there is only the need to convert the argument into
+% the correct form, and add a $0$ penalty at the end to nullify the effect of
+% repeating the last value.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_set_display_widow_penalties:n #1
+ {
+ \etex_displaywidowpenalties:D
+ \int_eval:w \clist_length:n {#1} + \c_one \int_eval_end:
+ \clist_map_function:nN {#1} \galley_set_aux:n
+ \c_zero
+ }
+\cs_generate_variant:Nn \galley_set_display_widow_penalties:n { V , v }
+\cs_new_protected_nopar:Npn \galley_set_widow_penalties:n #1
+ {
+ \etex_widowpenalties:D
+ \int_eval:w \clist_length:n {#1} + \c_one \int_eval_end:
+ \clist_map_function:nN {#1} \galley_set_aux:n
+ \c_zero
+ }
+\cs_generate_variant:Nn \galley_set_widow_penalties:n { V , v }
+\cs_new_nopar:Npn \galley_set_aux:n #1 { #1 ~ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \galley_set_club_penalties:n,
+% \galley_set_club_penalties:V,
+% \galley_set_club_penalties:v,
+% \galley_set_interline_penalties:n,
+% \galley_set_interline_penalties:V,
+% \galley_set_interline_penalties:v
+% }
+% Setting club or special line penalties is easy, as these are handled
+% mainly by the interline set up function. The two concepts are essentially
+% the same, but having two takes makes some special effects easier to
+% carry out.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_set_club_penalties:n #1
+ {
+ \clist_set:Nn \l_galley_club_penalties_clist {#1}
+ \galley_calc_interline_penalties:
+ }
+\cs_generate_variant:Nn \galley_set_club_penalties:n { V , v }
+\cs_new_protected_nopar:Npn \galley_set_interline_penalties:n #1
+ {
+ \clist_set:Nn \l_galley_line_penalties_clist {#1}
+ \galley_calc_interline_penalties:
+ }
+\cs_generate_variant:Nn \galley_set_interline_penalties:n { V , v }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \galley_set_display_club_penalties:n,
+% \galley_set_display_club_penalties:V,
+% \galley_set_display_club_penalties:v
+% }
+% Setting the display club penalties means first setting the primitive,
+% then recalculating the interline array to allow for these new values.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_set_display_club_penalties:n #1
+ {
+ \etex_clubpenalties:D
+ \int_eval:w \clist_length:n {#1} + \c_one \int_eval_end:
+ \clist_map_function:nN {#1} \galley_set_aux:n
+ \c_zero
+ \galley_calc_interline_penalties:
+ }
+\cs_generate_variant:Nn \galley_set_display_club_penalties:n { V , v }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\galley_set_interline_penalty:n}
+% \begin{macro}[aux]{\galley_set_interline_penalty_aux:nn}
+% \begin{macro}[aux]
+% {
+% \galley_set_interline_penalty_aux_i:n,
+% \galley_set_interline_penalty_aux_ii:n
+% }
+% Dealing with the general interline penalty is handled in one shot.
+% The idea is that for lines with no special penalty, the old general
+% penalty is removed and the new one is added. If there is currently
+% no shape set, then after adding the general interline value the
+% generic build system is invoked (in case the
+% \cs{etex_interlinepenalties:D} has accidentally been cleared).
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_set_interline_penalty:n #1
+ {
+ \int_compare:nNnTF { \etex_interlinepenalties:D \c_zero } = \c_zero
+ {
+ \etex_interlinepenalties:D \c_one \int_eval:w #1 \int_eval_end:
+ \galley_calc_interline_penalties:
+ }
+ {
+ \cs_set_nopar:Npn \galley_set_interline_penalty_aux_ii:n ##1
+ {
+ \int_eval:w
+ \etex_interlinepenalties:D ##1
+ - \etex_interlinepenalties:D \etex_interlinepenalties:D \c_zero
+ + #1
+ \int_eval_end:
+ }
+ \exp_args:Nf \galley_set_interline_penalty_aux:nn
+ { \clist_length:N \l_galley_line_penalties_clist } {#1}
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_set_interline_penalty_aux:nn #1#2
+ {
+ \etex_interlinepenalties:D
+ \etex_interlinepenalties:D \c_zero
+ \prg_stepwise_function:nnnN \c_one \c_one {#1}
+ \galley_set_interline_penalty_aux_i:n
+ \prg_stepwise_function:nnnN { #1 + \c_one } \c_one
+ { \etex_interlinepenalties:D \c_zero - \c_one }
+ \galley_set_interline_penalty_aux_ii:n
+ \int_eval:w #2 \int_eval_end:
+ }
+\cs_new_nopar:Npn \galley_set_interline_penalty_aux_i:n #1
+ { \etex_interlinepenalties:D \int_eval:w #1 \int_eval_end: }
+\cs_new_nopar:Npn \galley_set_interline_penalty_aux_ii:n #1 { }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\galley_calc_interline_penalties:}
+% \begin{macro}[aux]{\galley_calc_interline_penalties_aux:nn}
+% \begin{macro}[aux]
+% {
+% \galley_calc_interline_penalties_aux_i:n,
+% \galley_calc_interline_penalties_aux_ii:n
+% }
+% The underlying interline penalty array has to deal with club penalties,
+% display club penalties and any special line penalties, and include
+% the general interline penalty. These requirements lead to a rather
+% complex requirement on how many lines to deal with. This is needed twice,
+% so an \texttt{f}-type expansion is used to make life a little less
+% complex.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_calc_interline_penalties:
+ {
+ \exp_args:Nff \galley_calc_interline_penalties_aux:nn
+ {
+ \int_eval:n
+ {
+ \int_max:nn
+ {
+ \clist_length:N \l_galley_club_penalties_clist
+ + \c_one
+ }
+ {
+ \int_max:nn
+ {
+ \clist_length:N \l_galley_line_penalties_clist
+ + \c_one
+ }
+ { \etex_clubpenalties:D \c_zero }
+ }
+ }
+ }
+ { \clist_length:N \l_galley_line_penalties_clist }
+ }
+% \end{macrocode}
+% The idea is now to calculate the correct penalties. Two auxiliary functions
+% are used: one for any \enquote{special penalty} lines and a second for
+% normal lines. At the end of the process, the standard interline
+% penalty is always included.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_calc_interline_penalties_aux:nn
+ #1#2
+ {
+ \etex_interlinepenalties:D #1 ~
+ \prg_stepwise_function:nnnN \c_one \c_one {#2}
+ \galley_calc_interline_penalties_aux_i:n
+ \prg_stepwise_function:nnnN { #2 + \c_one } \c_one { #1 - \c_one }
+ \galley_calc_interline_penalties_aux_ii:n
+ \etex_interlinepenalties:D \etex_interlinepenalties:D \c_zero
+ }
+\cs_new_nopar:Npn \galley_calc_interline_penalties_aux_i:n
+ #1
+ {
+ \int_eval:w
+ \clist_item:Nn \l_galley_line_penalties_clist { #1 - \c_one }
+ + 0 \clist_item:Nn \l_galley_club_penalties_clist
+ { #1 - \c_one }
+ - \etex_clubpenalties:D #1 ~
+ \int_eval_end:
+ }
+\cs_new_nopar:Npn \galley_calc_interline_penalties_aux_ii:n
+ #1
+ {
+ \int_eval:w
+ \etex_interlinepenalties:D \etex_interlinepenalties:D \c_zero
+ + 0 \clist_item:Nn \l_galley_club_penalties_clist
+ { #1 - \c_one }
+ - \etex_clubpenalties:D #1 ~
+ \int_eval_end:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \galley_save_club_penalties:N,
+% \galley_save_interline_penalties:N,
+% \galley_save_display_club_penalties:N,
+% \galley_save_display_widow_penalties:N,
+% \galley_save_widow_penalties:N
+% }
+% \begin{macro}[aux]
+% {
+% \galley_save_display_club_penalties_aux:n,
+% \galley_save_display_widow_penalties_aux:n,
+% \galley_save_widow_penalties_aux:n
+% }
+% \begin{macro}{\galley_interline_penalty:}
+% Saving the array penalties varies in complexity depending on how they are
+% stored internally. The first two are easy: these are simply copies.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_save_club_penalties:N #1
+ { \clist_set_eq:NN #1 \l_galley_club_penalties_clist }
+\cs_new_protected_nopar:Npn \galley_save_interline_penalties:N #1
+ { \clist_set_eq:NN #1 \l_galley_line_penalties_clist }
+% \end{macrocode}
+% These all require appropriate mappings, using the fact that
+% \cs{clist_set:Nx} will tidy up the excess comma.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_save_display_club_penalties:N #1
+ {
+ \clist_set:Nx #1
+ {
+ \prg_stepwise_function:nnnN \c_one \c_one
+ { \etex_clubpenalties:D \c_zero - \c_one }
+ \galley_save_display_club_penalties:_aux:n
+ }
+ }
+\cs_new_nopar:Npn \galley_save_display_club_penalties:_aux:n #1
+ { \int_use:N \etex_clubpenaltes:D \int_eval:w #1 \int_eval_end: , }
+\cs_new_protected_nopar:Npn \galley_save_display_widow_penalties:N #1
+ {
+ \clist_set:Nx #1
+ {
+ \prg_stepwise_function:nnnN \c_one \c_one
+ { \etex_displaywidowpenalties:D \c_zero - \c_one }
+ \galley_save_display_widow_penalties:_aux:n
+ }
+ }
+\cs_new_nopar:Npn \galley_save_display_widow_penalties:_aux:n #1
+ { \int_use:N \etex_displaywidowpenalties:D \int_eval:w #1 \int_eval_end: , }
+\cs_new_protected_nopar:Npn \galley_save_widow_penalties:N #1
+ {
+ \clist_set:Nx #1
+ {
+ \prg_stepwise_function:nnnN \c_one \c_one
+ { \etex_widowpenalties:D \c_zero - \c_one }
+ \galley_save_widow_penalties:_aux:n
+ }
+ }
+\cs_new_nopar:Npn \galley_save_widow_penalties:_aux:n #1
+ { \int_use:N \etex_widowpenalties:D \int_eval:w #1 \int_eval_end: , }
+% \end{macrocode}
+% This one is not an array, but is stored in a primitive, so there is
+% a simple conversion. The general interline penalty is always the
+% last value in the primitive array.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \galley_interline_penalty:
+ { \int_use:N \etex_interlinepenalties:D \etex_interlinepenalties:D \c_zero }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{\LaTeXe{} fixes}
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% Purely for testing, some internal \LaTeXe{} functions are altered to work
+% with the mechanism here. This material is not comprehensive: additions are
+% made as-needed for test purposes.
+%
+% \begin{macro}{\@afterheading}
+% Set some flags and hope for the best!
+% \begin{macrocode}
+\cs_set_protected_nopar:Npn \@afterheading
+ {
+ \bool_gset_true:N \g_galley_no_break_next_bool
+ \if@afterindent
+ \else
+ \bool_gset_true:N \galley_omit_next_indent_bool
+ \fi
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@hangfrom}
+% The \cs{tex_handindent:D} primitive is no longer used, so the paragraph
+% shape is set in a different way. As a result, the label is part of the
+% same paragraph as the main body, hence the need to leave vertical mode.
+% \begin{macrocode}
+\cs_set_protected:Npn \@hangfrom #1
+ {
+ \setbox \@tempboxa = \hbox { {#1} }
+ \galley_parshape_single_par:nnnN
+ \c_one
+ { \box_wd:N \@tempboxa }
+ \c_zero_dim
+ \c_false_bool
+ \bool_gset_true:N \g_galley_no_break_next_bool
+ \bool_gset_true:N \galley_omit_next_indent_bool
+ \box \@tempboxa
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@makefntext}
+% Here, the paragraph indent is set up using the template system, and
+% as in other places the code ensures that the label is set in horizontal
+% mode. The flag used for omitting the indent is once again the galley
+% one.
+% \begin{macrocode}
+\cs_set_protected:Npn \@makefntext #1
+ {
+ \UseTemplate { justification } { std } { indent-width = 1 em }
+ \bool_gset_true:N \galley_omit_next_indent_bool
+ \galley_leave_vmode:
+ \hb@xt@ 1.8em { \hss \@makefnmark } #1
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex \ No newline at end of file
diff --git a/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx b/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx
new file mode 100644
index 00000000000..0dc1c85b610
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.dtx
@@ -0,0 +1,1602 @@
+% \iffalse
+%
+%% File: xgalley.dtx Copyright (C) 1999-2001, 2004-2009 Frank Mittelbach
+%% (C) 2010,2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX Project Team.
+%%
+%% -----------------------------------------------------------------------
+%%
+%
+%<*driver|package>
+\RequirePackage{l3names}
+\GetIdInfo$Id: xgalley.dtx 2895 2011-10-09 15:58:19Z joseph $
+ {L3 Experimental galley}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \textsf{xgalley} package\\ Galley^^A
+% \thanks{This file describes v\ExplFileVersion,
+% last revised \ExplFileDate.}^^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 \ExplFileDate}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \section{Introduction}
+%
+% In \LaTeX3 terminology a galley is a rectangular area which receives
+% text and other material filling it from top. The vertically extend of
+% a galley is normally not restricted: instead certain chunks are taken
+% off the top of an already partially filled galley to form columns or
+% similar areas on a page. This process is typically asynchronous but
+% there are ways to control or change its behaviour.
+%
+% Examples for galleys are \enquote{the main galley}, where the
+% continuous document data gets formatted into and from which columns
+% and pages are constructed, and \enquote{vertical box galleys}, such
+% as the body of a minipage environment. The latter galleys are
+% typically not split after formatting, though there can be exceptions.
+%
+% \section{Formatting layers}
+%
+% The present module is mainly concerned with the formatting of text
+% in galleys. The mechanism by which this is achieved uses four
+% (somewhat) distinct layers, some of which can be addressed using the
+% templates provided here.
+%
+% \subsection{Layer one: external dimensions}
+%
+% The bottom layer of the system is the external dimensions of the
+% galley. Normally only the horizontal dimension is fixed externally,
+% while the vertical (filling) dimension is unspecified. The external
+% dimensions are fixed when starting a new galley, and are therefore
+% not modifiable within the galley.
+%
+% There are no templates for setting this layer directly, although the
+% external values are influenced by other parts of the system (for
+% example when creating minipage environments).
+%
+% \subsection{Layer two: internal dimensions}
+%
+% The second layer is the internal dimensions of the galley: the
+% \emph{measure} used for paragraph text and the position of the
+% paragraph relative to the edges of the galley.
+%
+% This layer is normally accessed by higher-level templates
+% \emph{via} the object type \texttt{measure}. Changes made using
+% level two templates will often extend for large parts of a document
+% (up to and including the entire document).
+%
+% \subsection{Layer three: paragraph shape}
+%
+% The third layer defines the paragraph shape within the measure as
+% provided by the second layer. In the absence of any specification
+% for that layer the paragraph shape used will be that of a
+% rectangular area of the width of the current measure.
+%
+% There are some restrictions imposed on the shape of a paragraph by the
+% underlying \TeX{} mechanisms. For example, cut out sections in
+% paragraphs can be specified from the top of the paragraph but not from
+% the bottom.
+%
+% \subsection{Layer four: formatting inside the paragraph}
+%
+% The forth layer deals with the paragraph formatting aspects such as
+% hyphenation and justification within the paragraph (this is sometimes
+% referred to as \enquote{\texttt{h\&j}} or \enquote{\texttt{hj}}).
+%
+% \section{Templates}
+%
+% \subsection{Layer two: internal dimensions}
+%
+% \begin{TemplateInterfaceDescription}{measure}
+% \TemplateArgument{}{} ^^A A hack
+% \TemplateSemantics
+% Sets the width available to typeset material within the galley.
+% The \meta{left margin} and \meta{right margin} values are used in the
+% adjustment to over-ride any given in the template. Depending upon
+% the template in use, the margins may be absolute (relative only to the
+% edges of the galley) or relative (taking account of |measure| adjustments
+% already made). The template applies to the galley from the point of
+% us forward, unless over-ridden by another use of the |measure|
+% object type.
+% \end{TemplateInterfaceDescription}
+%
+% \begin{TemplateDescription}{measure}{absolute}
+% \TemplateKey{left-margin}{length}
+% {^^A
+% The distance from the left edge of the galley to the left edge of
+% the area for typeset material. A negative value will cause the
+% typeset material to extend beyond the edge of the galley.^^A
+% }
+% {0 pt}
+% \TemplateKey{right-margin}{length}
+% {^^A
+% The distance from the right edge of the galley to the right edge of
+% the area for typeset material. A negative value will cause the
+% typeset material to extend beyond the edge of the galley.^^A
+% }
+% {0 pt}
+% \TemplateSemantics
+% This template sets up the typesetting area such that typeset material
+% runs from |left-margin| away from the left edge of the galley to
+% |right-margin| away from the right edge of the galley. Both of these
+% distances are absolute, \emph{i.e.}~no account is taken of previous
+% |measure| settings. Either on or both values may be negative, in which
+% case the typeset material will protrude outside of the edges of the
+% galley.
+% \end{TemplateDescription}
+%
+% \begin{TemplateDescription}{measure}{relative}
+% \TemplateKey{left-margin}{length}
+% {^^A
+% The distance from the previous left margin of the typeset material
+% within the galley to the new position of the left margin. A negative
+% value will cause the new margin to be \enquote{outside} of the
+% previous one, and \emph{may} cause the typeset material to
+% protrude outside of the edge of the galley.
+% }
+% {0 pt}
+% \TemplateKey{right-margin}{length}
+% {^^A
+% The distance from the previous right margin of the typeset material
+% within the galley to the new position of the right margin. A negative
+% value will cause the new margin to be \enquote{outside} of the
+% previous one, and \emph{may} cause the typeset material to
+% protrude outside of the edge of the galley.
+% }
+% {0 pt}
+% \TemplateSemantics
+% This template sets up the typesetting area such that it has margins
+% |left-margin| and |right-margin| within those previously set. For a
+% galley within no previous margins, this will result in margins relative
+% to the edges of the galley. Within a galley in which the |measure| has
+% already been set, using the |relative| template will indent the typeset
+% material relative to the existing margins.
+% Either on or both values may be negative, in which
+% case the typeset material may protrude outside of the edges of the
+% galley.
+% \end{TemplateDescription}
+%
+% \subsection{Layer three: paragraph shape}
+%
+% \begin{TemplateInterfaceDescription}{parshape}
+% \TemplateArgument{}{}^^A A hack
+% \TemplateSemantics
+% Template of this type define any shaping of the paragraph within the
+% current measure of the galley. Thus they are used to generate
+% \enquote{special} paragraph shapes, for example placing a cutout
+% in one side of the paragraph. Typically, \texttt{parshape} templates
+% will apply in a limited sense (to a single paragraph or a defined number of
+% lines). However, \texttt{parshape} templates may also apply in an
+% \enquote{ongoing} manner.
+%
+% Note that \texttt{parshape} templates do not alter any first-line
+% indent for paragraphs (or any other \enquote{in paragraph} setting).
+% Instead, they define a shape inside which the paragraph material will be
+% placed.
+% \end{TemplateInterfaceDescription}
+%
+% \begin{TemplateDescription}{parshape}{hang}
+% \TemplateKey{indent}{length}
+% {^^A
+% The hanging indent from either the left- or right-hand margin
+% (as determined by \texttt{on-left-side}).^^A
+% }
+% {0 pt}
+% \TemplateKey{on-left-side}{boolean}
+% {^^A
+% If \texttt{true}, causes the hanging indent to be on the left-hand
+% side of the paragraph.^^A
+% }
+% {true}
+% \TemplateKey{lines}{integer}
+% {The number of lines of full width before hanging begins.}
+% {1}
+% \TemplateSemantics
+% Sets the paragraph shape such that the after a number of full-width
+% lines, specified by |lines|, the paragraph is indented by the
+% |indent| from a margin. If |on-left-side| is |true| this indent will be
+% from the left-hand margin, otherwise it will be from the right. In either
+% case, the indent is relative to the edge of the current |measure| and
+% may be negative (in which case an outdent will result).
+% This template type applies only to a single paragraph.
+% \end{TemplateDescription}
+%
+% \begin{TemplateDescription}{parshape}{initial}
+% \TemplateKey{indent}{length}
+% {^^A
+% The indent for the initial lines from either the left- or right-hand
+% margin (as determined by \texttt{on-left-side}).^^A
+% }
+% {0 pt}
+% \TemplateKey{on-left-side}{boolean}
+% {^^A
+% If \texttt{true}, causes the indent to be on the left-hand
+% side of the paragraph.^^A
+% }
+% {true}
+% \TemplateKey{lines}{integer}
+% {The number of lines of indented lines before full-width line begins.}
+% {2}
+% \TemplateSemantics
+% Sets the paragraph shape such that the first |lines| lines
+% are indented by the |indent| given, before lines of full width begin.
+% If |on-left-side| is |true| this indent will be
+% from the left-hand margin, otherwise it will be from the right. In either
+% case, the indent is relative to the edge of the current |measure| and
+% may be negative (in which case an outdent will result).
+% This template type applies only to a single paragraph.
+% \end{TemplateDescription}
+%
+% \begin{TemplateDescription}{parshape}{std}
+% \TemplateKey{}{}{}{} ^^A hack
+% \TemplateSemantics
+% Sets a rectangular paragraph shape which occupies the full width
+% specified by the |measure|. It is therefore intended as a
+% \enquote{do nothing} template for use where a paragraph shape is required
+% but where no special formatting is needed. This template type applies only
+% to a single paragraph.
+% \end{TemplateDescription}
+%
+% \subsection{Layer four: formatting inside the paragraph}
+%
+% \begin{TemplateInterfaceDescription}{hyphenation}
+% \TemplateArgument{}{} ^^A Hack
+% \TemplateSemantics
+% Controls whether hyphenation is attempted within the current
+% galley. This object type may also alter the degree to which hyphenation
+% is encouraged by manipulating the underlying \TeX{} parameters. This
+% object type applies to the galley from the point of use forward.
+% \end{TemplateInterfaceDescription}
+%
+% \begin{TemplateDescription}{hyphenation}{std}
+% \TemplateKey{enable}{boolean}
+% {Switches all hyphenation on or off.}
+% {true}
+% \TemplateKey{enable-upper-case}
+% {boolean}
+% {^^A
+% Switches hyphenation on or off for words beginning with upper case
+% letters.^^A
+% }
+% {true}
+% \TemplateKey{penalty}{choice}
+% {^^A
+% Sets the degree to which \TeX{} is discouraged from undertaking
+% hyphenation, from the choices |low|, |medium| and |high|.^^A
+% }
+% {low}
+% \TemplateSemantics
+% Determines both whether hyphenation is allowed at all, and if so to
+% what degree it is discouraged. Setting |penalty| to |high| does not
+% prevent hyphenation: this is only done if |enable| is set |false|.
+% \end{TemplateDescription}
+%
+% \begin{TemplateInterfaceDescription}{justification}
+% \TemplateArgument{}{} ^^A Hack
+% \TemplateSemantics
+% Controls the nature of justification undertaken within the galley.
+% The template applies from the point of use forward.
+% \end{TemplateInterfaceDescription}
+%
+% \begin{TemplateDescription}{justification}{std}
+% \TemplateKey{end-skip}{skip}
+% {The skip inserted to fill the last line of a paragraph.}
+% {0 pt plus 1 fil}
+% \TemplateKey{fixed-word-spacing}{boolean}
+% {^^A
+% Determines whether inter-word spacing has a stretch component (for
+% non-monospaced fonts.^^A
+% }
+% {false}
+% \TemplateKey{indent-width}{length}
+% {^^A
+% The length of the indent inserted at the start of the first line of a
+% new paragraph.^^A
+% }
+% {}
+% \TemplateKey{left-skip}{skip}
+% {^^A
+% The skip between the left margin of the galley and the left edge of a
+% paragraph.^^A
+% }
+% {0 pt}
+% \TemplateKey{right-skip}{skip}
+% {^^A
+% The skip between the right margin of the galley and the right edge of a
+% paragraph.^^A
+% }
+% {0 pt}
+% \TemplateKey{start-skip}{skip}
+% {^^A
+% The skip inserted in addition to |indent-width| at the start of a
+% paragraph.^^A
+% }
+% {0 pt}
+% \TemplateSemantics
+% The |std| template for justification provides rubber lengths
+% at the start and end of the paragraph and at each side of the paragraph.
+% It also allows for both flexible and fixed inter-word spacing. The
+% interaction between the settings is demonstrated in the selection of
+% standard instances provided.
+% \end{TemplateDescription}
+%
+% \begin{InstanceDescription}{justification}{justified}{std}
+% \InstanceKey{indent-width}{15 pt}
+% \InstanceSemantics
+% Sets paragraphs fully-justified with the first line indented by
+% |15 pt|.
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{justification}{noindent}{std}
+% \InstanceKey{end-skip}{15 pt plus 1 fil}
+% \InstanceKey{indent-width}{0 pt}
+% \InstanceSemantics
+% Sets paragraphs fully-justified with no indent for the first line. To
+% ensure that paragraphs have some visual distinction, the |end-skip| is
+% set to insert some space in all cases.
+% \end{InstanceDescription}
+%
+% \begin{TemplateDescription}{justification}{single}
+% \TemplateKey{end-skip}{skip}
+% {The skip inserted to fill the last line of a paragraph.}
+% {0 pt plus 1 fil}
+% \TemplateKey{fixed-word-spacing}{boolean}
+% {^^A
+% Determines whether inter-word spacing has a stretch component (for
+% non-monospaced fonts.^^A
+% }
+% {false}
+% \TemplateKey{indent-width}{length}
+% {^^A
+% The length of the indent inserted at the start of the first line of a
+% new paragraph.^^A
+% }
+% {}
+% \TemplateKey{left-skip}{skip}
+% {^^A
+% The skip between the left margin of the galley and the left edge of a
+% paragraph.^^A
+% }
+% {0 pt}
+% \TemplateKey{right-skip}{skip}
+% {^^A
+% The skip between the right margin of the galley and the right edge of a
+% paragraph.^^A
+% }
+% {0 pt}
+% \TemplateKey{start-skip}{skip}
+% {^^A
+% The skip inserted in addition to |indent-width| at the start of a
+% paragraph.^^A
+% }
+% {0 pt}
+% \TemplateKey{stretch-last-line}{boolean}
+% {
+% Determines whether inter-word spacing in the last line is stretched.
+% If \texttt{true}, the spacing in the last line is stretched in the
+% by the same factor as that in the penultimate line.^^A
+% }
+% {false}
+% \TemplateSemantics
+% The |single| template for justification provides rubber lengths
+% at the start and end of the paragraph and at each side of the paragraph.
+% It also allows for both flexible and fixed inter-word spacing. The
+% interaction between the settings is demonstrated in the selection of
+% standard instances provided. The template applies only to a single
+% paragraph.
+% \end{TemplateDescription}
+%
+% \begin{InstanceDescription}{justification}{centered}{std}
+% \InstanceKey{end-skip}{0 pt}
+% \InstanceKey{fixed-word-spacing}{true}
+% \InstanceKey{indent-width}{0 pt}
+% \InstanceKey{left-skip}{0 pt plus 1 em}
+% \InstanceKey{right-skip}{0 pt plus 1 em}
+% \InstanceSemantics
+% Centres typeset material such that hyphenation will still occur and
+% such that very short lines are discouraged. This is similar to the
+% \LaTeXe{} \pkg{ragged2e} \env{Centering} environment.
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{justification}{ragged-left}{std}
+% \InstanceKey{end-skip}{0 pt}
+% \InstanceKey{fixed-word-spacing}{true}
+% \InstanceKey{indent-width}{0 pt}
+% \InstanceKey{left-skip}{0 pt plus 2 em}
+% \InstanceKey{right-skip}{0 pt}
+% \InstanceSemantics
+% Typesets material with a ragged left margin such that hyphenation will
+% still occur and such that very short lines are discouraged. This is
+% similar to the \LaTeXe{} \pkg{ragged2e} \env{RaggedLeft} environment.
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{justification}{ragged-right}{std}
+% \InstanceKey{end-skip}{0 pt}
+% \InstanceKey{fixed-word-spacing}{true}
+% \InstanceKey{indent-width}{0 pt}
+% \InstanceKey{left-skip}{0 pt}
+% \InstanceKey{right-skip}{0 pt plus 2 em}
+% \InstanceSemantics
+% Typesets material with a ragged right margin such that hyphenation will
+% still occur and such that very short lines are discouraged. This is
+% similar to the \LaTeXe{} \pkg{ragged2e} \env{RaggedLeft} environment.
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{justification}{center}{std}
+% \InstanceKey{end-skip}{0 pt}
+% \InstanceKey{fixed-word-spacing}{true}
+% \InstanceKey{indent-width}{0 pt}
+% \InstanceKey{left-skip}{0 pt plus 1 fil}
+% \InstanceKey{right-skip}{0 pt plus 1 fil}
+% \InstanceSemantics
+% Centres typeset material such that hyphenation is strongly discouraged
+% and short lines are allowed. This template is suited to centring arbitrary
+% material (such as boxes) rather than centring text. In the later case, the
+% |centered| instance should be used.
+% \end{InstanceDescription}
+%
+% \begin{TemplateDescription}{justification}{compound}
+% \TemplateKey{first-paragraph}{instance}
+% {Justification for the first paragraph.}
+% {}
+% \TemplateKey{other-paragraphs}{instance}
+% {Justification for the remaining paragraphs.}
+% {}
+% \TemplateSemantics
+% Here, both keys should themselves be instances of the |justification|
+% template. The |compound| template is used to set up a single
+% \enquote{non-standard} paragraph followed by \enquote{standard} ones.
+% For example, it can be used to ensure that one |noindent| paragraph is
+% then followed by |std| justification.
+% \end{TemplateDescription}
+%
+% \begin{TemplateInterfaceDescription}{line-breaking}
+% \TemplateArgument{}{} ^^A Hack
+% \TemplateSemantics
+% Controls the line breaking attempted by \TeX{} when typesetting
+% material for the galley. This does not include whether words are
+% hyphenated, which is handled separately.
+% \end{TemplateInterfaceDescription}
+%
+% \begin{TemplateDescription}{line-breaking}{std}
+% \TemplateKey{badness}{integer}
+% {^^A
+% Boundary that if exceeded will cause \TeX{} to report an
+% underfull line.^^A
+% }
+% {1000}
+% \TemplateKey{binop-penalty}{integer}
+% {^^A
+% Penalty charged if an inline math formula is broken at a
+% binary operator.^^A
+% }
+% {700}
+% \TemplateKey{double-hyphen-demerits}{integer}
+% {^^A
+% Extra demerit charge of two (or more) lines in succession end
+% in a hyphen.^^A
+% }
+% {10 000}
+% \TemplateKey{emergency-stretch}{skip}
+% {^^A
+% Additional stretch assumed for each line if no better line breaking
+% can be found without it. This stretch is not actually added to lines,
+% so its use may result in underfull box warnings.^^A
+% }
+% {0 pt}
+% \TemplateKey{final-hyphen-demerits}{integer}
+% {Extra demerit charge if the second last line is hyphenated.}
+% {5000}
+% \TemplateKey{fuzz}{length}
+% {Boundary below overfull lines are not reported.}
+% {0.1 pt}
+% \TemplateKey{mismatch-demerits}{integer}
+% {^^A
+% Extra demerit charge if two visually incompatible lines follow
+% each other.^^A
+% }
+% {10000}
+% \TemplateKey{line-penalty}{integer}
+% {^^A
+% Extra penalty charged per line in the paragraph. By making
+% this penalty higher \TeX{} will try harder to produce compact
+% paragraphs.^^A
+% }
+% {10}
+% \TemplateKey{pretolerance}{integer}
+% {^^A
+% Maximum tolerance allowed for individual lines to break the
+% paragraph without attempting hyphenation.^^A
+% }
+% {100}
+% \TemplateKey{relation-penalty}{integer}
+% {^^A
+% Penalty charged if an inline math formula is broken at a
+% relational symbol.^^A
+% }
+% {500}
+% \TemplateKey{tolerance}{integer}
+% {^^A
+% Maximum tolerance allowed for individual lines when breaking a
+% paragraph while attempting hyphenation (if this limit can't be
+% met \texttt{emergency-stretch} comes into play).^^A
+% }
+% {200}
+% \TemplateSemantics
+% This is an interface to the underlying \TeX{} system for determining
+% line breaking.
+% \end{TemplateDescription}
+%
+% \subsection{Between paragraphs}
+%
+% \begin{TemplateInterfaceDescription}{paragraph-breaking}
+% \TemplateArgument{}{} ^^A Hack
+% \TemplateSemantics
+% This object type determines how \TeX{} determines the behaviour when
+% the paragraph-breaking algorithm is calculating whether to break up a
+% paragraph. Thus for example an instance of this object type may prevent
+% breaks within a paragraph, forbid widows or orphans, \emph{etc.}
+% \end{TemplateInterfaceDescription}
+%
+% \begin{TemplateDescription}{paragraph-breaking}{std}
+% \TemplateKey{badness}{integer}
+% {^^A
+% Boundary that if exceeded will cause \TeX{} to report an
+% underfull vertical box.^^A
+% }
+% {1000}
+% \TemplateKey{broken-penalty}{integer}
+% {Penalty for page breaking after a hyphenated line.}
+% {100}
+% \TemplateKey{club-penalty}{integer}
+% {Penalty for generating a club line when page breaking.}
+% {150}
+% \TemplateKey{display-club-penalty}{integer}
+% {^^A
+% Penalty for breaking between to leave a club line after display
+% math.^^A
+% }
+% {150}
+% \TemplateKey{display-widow-penalty}{integer}
+% {^^A
+% Penalty for breaking between to leave a widow line before display
+% math.^^A
+% }
+% {150}
+% \TemplateKey{fuzz}{length}
+% {Boundary below which overfull vertical boxes are not reported.}
+% {0.1 pt}
+% \TemplateKey{interline-penalty}{integer}
+% {Penalty for breaking between lines in a paragraph.}
+% {0}
+% \TemplateKey{pre-display-penalty}{integer}
+% {Penalty for breaking between immediately before display math material.}
+% {10 000}
+% \TemplateKey{post-display-penalty}{integer}
+% {Penalty for breaking between immediately after display math material.}
+% {0}
+% \TemplateKey{widow-penalty}{integer}
+% {Penalty for generating a widow line when page breaking.}
+% {150}
+% \TemplateSemantics
+% This template provides an interface to the underlying \TeX{} mechanism for
+% controlling page breaking. The template applies on an ongoing basis to all
+% paragraphs after the template is used.
+% \end{TemplateDescription}
+%
+% \begin{InstanceDescription}{paragraph-breaking}{std}{std}
+% \InstanceSemantics
+% Sets paragraphs such that they can break with widows and orphans
+% discouraged but not prevented. Breaks are possible after display math
+% material but no immediately before it.
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{paragraph-breaking}{nobreak}{std}
+% \InstanceKey{interline-penalty}{10 000}
+% \InstanceKey{post-display-penalty}{10 000}
+% \InstanceSemantics
+% Sets paragraphs such that they cannot be broken at all (as far as is
+% possible in \TeX{}).
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{paragraph-breaking}{nolone}{std}
+% \InstanceKey{club-penalty}{10 000}
+% \InstanceKey{display-widow-penalty}{10 000}
+% \InstanceKey{widow-penalty}{10 000}
+% \InstanceSemantics
+% Sets paragraphs such that they cannot be broken to leave a club or
+% widow line (as far as is possible in \TeX{}).
+% \end{InstanceDescription}
+%
+% \begin{TemplateDescription}{paragraph-breaking}{single}
+% \TemplateKey{badness}{integer}
+% {^^A
+% Boundary that if exceeded will cause \TeX{} to report an
+% underfull vertical box.^^A
+% }
+% {\meta{none}}
+% \TemplateKey{broken-penalty}{integer}
+% {Penalty for page breaking after a hyphenated line.}
+% {\meta{none}}
+% \TemplateKey{club-penalty}{integer}
+% {Penalty for generating a club line when page breaking.}
+% {\meta{none}}
+% \TemplateKey{display-club-penalty}{integer}
+% {^^A
+% Penalty for breaking between to leave a club line after display
+% math.^^A
+% }
+% {\meta{none}}
+% \TemplateKey{display-widow-penalty}{integer}
+% {^^A
+% Penalty for breaking between to leave a widow line before display
+% math.^^A
+% }
+% {\meta{none}}
+% \TemplateKey{fuzz}{length}
+% {Boundary below which overfull vertical boxes are not reported.}
+% {\meta{none}}
+% \TemplateKey{interline-penalty}{integer}
+% {Penalty for breaking between lines in a paragraph.}
+% {\meta{none}}
+% \TemplateKey{pre-display-penalty}{integer}
+% {Penalty for breaking between immediately before display math material.}
+% {\meta{none}}
+% \TemplateKey{post-display-penalty}{integer}
+% {Penalty for breaking between immediately after display math material.}
+% {\meta{none}}
+% \TemplateKey{widow-penalty}{integer}
+% {Penalty for generating a widow line when page breaking.}
+% {\meta{none}}
+% \TemplateSemantics
+% This template provides an interface to the underlying \TeX{} mechanism for
+% controlling page breaking. The template applies only to the next paragraph,
+% and can thus be used to achieve effects such as non-breaking paragraphs.
+% \end{TemplateDescription}
+%
+% \begin{InstanceDescription}{paragraph-breaking}{single-std}{single}
+% \InstanceSemantics
+% Sets the next paragraph such that it can break with widows and orphans
+% discouraged but not prevented. Breaks are possible after display math
+% material but no immediately before it.
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{paragraph-breaking}{single-nobreak}{single}
+% \InstanceKey{interline-penalty}{10 000}
+% \InstanceKey{post-display-penalty}{10 000}
+% \InstanceSemantics
+% Sets the next paragraph such that it cannot be broken at all (as far as is
+% possible in \TeX{}).
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{paragraph-breaking}{single-noclub}{single}
+% \InstanceKey{club-penalty}{10 000}
+% \InstanceKey{display-club-penalty}{10 000}
+% \InstanceSemantics
+% Sets the next paragraph such that it cannot be broken to leave a club
+% line (as far as is possible in \TeX{}).
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{paragraph-breaking}{single-nolone}{single}
+% \InstanceKey{club-penalty}{10 000}
+% \InstanceKey{display-club-penalty}{10 000}
+% \InstanceKey{display-widow-penalty}{10 000}
+% \InstanceKey{widow-penalty}{10 000}
+% \InstanceSemantics
+% Sets the next paragraph such that it cannot be broken to leave a club or
+% widow line (as far as is possible in \TeX{}).
+% \end{InstanceDescription}
+%
+% \begin{InstanceDescription}{paragraph-breaking}{single-nowidow}{single}
+% \InstanceKey{display-widow-penalty}{10 000}
+% \InstanceKey{widow-penalty}{10 000}
+% \InstanceSemantics
+% Sets the next paragraph such that it cannot be broken to leave a
+% widow line (as far as is possible in \TeX{}).
+% \end{InstanceDescription}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{xgalley} Implementation}
+%
+% This module provided a template-level interface for the \LaTeX3 galley. As
+% such, the code here is intended for design-level changes which apply to
+% large blocks. The variables provided are therefore used only for supporting
+% the templates, while any documented interfaces are in \pkg{l3galley}.
+%
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\RequirePackage{xparse,xtemplate,l3galley}
+% \end{macrocode}
+%
+% \subsection{Variables}
+%
+% \begin{variable}{\l_galley_tmpa_clist, \l_galley_tmpb_clist}
+% Scratch space.
+% \begin{macrocode}
+\clist_new:N \l_galley_tmpa_clist
+\clist_new:N \l_galley_tmpb_clist
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Layer two: internal dimensions}
+%
+% There is a single object type for level two, the \texttt{measure} for
+% the text in the galley. There are no arguments, as the measure is a design
+% concept.
+% \begin{macrocode}
+\DeclareObjectType { measure } { 0 }
+% \end{macrocode}
+%
+% There are two templates for galley measures: absolute and relative.
+% Both use the same interface.
+% \begin{macrocode}
+\DeclareTemplateInterface { measure } { absolute } { 0 }
+ {
+ left-margin : length = 0 pt ,
+ right-margin : length = 0 pt
+ }
+\DeclareTemplateInterface { measure } { relative } { 0 }
+ {
+ left-margin : length = 0 pt ,
+ right-margin : length = 0 pt
+ }
+% \end{macrocode}
+%
+% \begin{variable}{\l_galley_left_margin_dim, \l_galley_right_margin_dim}
+% In the \texttt{absolute} template, the two margin values are relative
+% to the edges of the galley. This means that any existing offset or
+% line-length adjustment are ignored.
+% \begin{macrocode}
+%<*package>
+\cs_new_eq:NN \l_galley_left_margin_dim \leftmargin
+%</package>
+%<*package>
+\cs_new_eq:NN \l_galley_right_margin_dim \rightmargin
+%</package>
+\DeclareTemplateCode { measure } { absolute } { 0 }
+ {
+ left-margin = \l_galley_left_margin_dim ,
+ right-margin = \l_galley_right_margin_dim
+ }
+ {
+ \AssignTemplateKeys
+ \galley_margins_set_absolute:nn \l_galley_left_margin_dim
+ \l_galley_right_margin_dim
+ }
+% \end{macrocode}
+% On the other hand, the \texttt{relative} template works relative to
+% the current indentation at both sides.
+% \begin{macrocode}
+\DeclareTemplateCode { measure } { relative } { 0 }
+ {
+ left-margin = \l_galley_left_margin_dim ,
+ right-margin = \l_galley_right_margin_dim
+ }
+ {
+ \AssignTemplateKeys
+ \galley_margins_set_relative:nn \l_galley_left_margin_dim
+ \l_galley_right_margin_dim
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Layer three: paragraph shape}
+%
+% The object type \texttt{parshape} is a somewhat extended interface
+% to the \TeX{} \cs{tex_parshape:D} primitive. As with the \texttt{measure},
+% the \texttt{parshape} template has no arguments as it is essentially a
+% design-oriented concept.
+% \begin{macrocode}
+\DeclareObjectType { parshape } { 0 }
+% \end{macrocode}
+%
+% There are two standard templates for paragraph shapes which do
+% something, both with the same interface. The \texttt{hang} template
+% provides one or more standard lines followed by a hanging paragraph,
+% while the \texttt{initial} template cuts out a space at the start of
+% the paragraph.
+% \begin{macrocode}
+\DeclareTemplateInterface { parshape } { hang } { 0 }
+ {
+ indent : length = 0 pt ,
+ on-left-side : boolean = true ,
+ lines : integer = 1
+ }
+\DeclareTemplateInterface { parshape } { initial } { 0 }
+ {
+ indent : length = 0 pt ,
+ on-left-side : boolean = true ,
+ lines : integer = 2
+ }
+% \end{macrocode}
+% \begin{variable}{\l_galley_parshape_indent_dim}
+% \begin{variable}{\l_galley_parshape_on_left_bool}
+% \begin{variable}{\l_galley_parshape_lines_int}
+% Both of the templates are implemented as special cases of the more
+% general function defined earlier.
+% \begin{macrocode}
+\DeclareTemplateCode { parshape } { hang } { 0 }
+ {
+ indent = \l_galley_parshape_indent_dim ,
+ on-left-side = \l_galley_parshape_on_left_bool ,
+ lines = \l_galley_parshape_lines_int
+ }
+ {
+ \AssignTemplateKeys
+ \bool_if:NTF \l_galley_parshape_on_left_bool
+ {
+ \galley_parshape_single_par:nVVN
+ \l_galley_parshape_lines_int
+ \l_galley_parshape_indent_dim
+ \c_zero_dim
+ \c_false_bool
+ }
+ {
+ \galley_parshape_single_par:nVVN
+ \l_galley_parshape_lines_int
+ \c_zero_dim
+ \l_galley_parshape_indent_dim
+ \c_false_bool
+ }
+ }
+\DeclareTemplateCode { parshape } { initial } { 0 }
+ {
+ indent = \l_galley_parshape_indent_dim ,
+ on-left-side = \l_galley_parshape_on_left_bool ,
+ lines = \l_galley_parshape_lines_int
+ }
+ {
+ \AssignTemplateKeys
+ \clist_clear:N \l_galley_tmpa_clist
+ \clist_clear:N \l_galley_tmpb_clist
+ \prg_replicate:nn { \l_galley_parshape_lines_int }
+ {
+ \clist_put_right:Nn \l_galley_tmpa_clist
+ { \l_galley_parshape_indent_dim }
+ \clist_put_right:Nn \l_galley_tmpb_clist
+ { \c_zero_dim }
+ }
+ \bool_if:NTF \l_galley_parshape_on_left_bool
+ {
+ \galley_parshape_single_par:nVVN
+ \c_zero
+ \l_galley_tmpa_clist
+ \l_galley_tmpb_clist
+ \c_true_bool
+ }
+ {
+ \galley_parshape_single_par:nVVN
+ \c_zero
+ \l_galley_tmpb_clist
+ \l_galley_tmpa_clist
+ \c_true_bool
+ }
+ }
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+% \end{variable}
+%
+% There is also a \enquote{do nothing} paragraph shape for cases where
+% a template is needed but no action is desirable.
+% \begin{macrocode}
+\DeclareTemplateInterface { parshape } { std } { 0 } { }
+\DeclareTemplateCode { parshape } { std } { 0 } { } { }
+% \end{macrocode}
+%
+% \subsection{Layer four: formatting inside the paragraph}
+%
+% The first type of object within a paragraph is the hyphenation. This
+% object needs no arguments.
+% \begin{macrocode}
+\DeclareObjectType { hyphenation } { 0 }
+% \end{macrocode}
+%
+% There is only hyphenation template as standard. This provides a
+% semi-flexible interface to the underlying \TeX{} methods. (The detail
+% is therefore hidden within the implementation phase.)
+% \begin{macrocode}
+\DeclareTemplateInterface { hyphenation } { std } { 0 }
+ {
+ enable : boolean = true ,
+ enable-upper-case : boolean = true ,
+ penalty : choice { low , medium , high } = low
+ }
+% \end{macrocode}
+% The implementation for hyphenation mainly sets low-level values.
+% The minimum number of characters after a hyphen is set directly,
+% whereas the number before is not. This is so that
+% \cs{tex_lefthyphenmin:D} can also be used to completely prevent
+% hyphenation.
+% \begin{macrocode}
+\DeclareTemplateCode { hyphenation } { std } { 0 }
+ {
+ enable = \l_galley_hyphen_enable_bool ,
+ enable-upper-case = \l_galley_hyphen_uppercase_bool ,
+ penalty =
+ {
+ low =
+ {
+ \int_set:Nn \tex_hyphenpenalty:D { 51 }
+ \int_set:Nn \tex_exhyphenpenalty:D { 51 }
+ } ,
+ medium =
+ {
+ \int_set:Nn \tex_hyphenpenalty:D { 151 }
+ \int_set:Nn \tex_exhyphenpenalty:D { 151 }
+ } ,
+ high =
+ {
+ \int_set:Nn \tex_hyphenpenalty:D { 301 }
+ \int_set:Nn \tex_exhyphenpenalty:D { 301 }
+ } ,
+ }
+ }
+ {
+ \AssignTemplateKeys
+ \int_set:Nn \tex_lefthyphenmin:D
+ {
+ \bool_if:NTF \l_galley_hyphen_enable_bool
+ { \l_galley_hyphen_left_int } { 63 }
+ }
+ \int_set:Nn \tex_uchyph:D
+ { \bool_if:NTF \l_galley_hyphen_uppercase_bool { 1 } { 0 } }
+ }
+% \end{macrocode}
+% At this stage, the default hyphenation character should be set and
+% hyphenation should be enabled.
+% \begin{macrocode}
+%\UseTemplate { hyphenation } { std } { }
+\tex_defaulthyphenchar:D 45 \scan_stop:
+% \end{macrocode}
+%
+% \begin{variable}{\l_galley_justification_other_tl}
+% Used for the reset system for justification: using this token list means
+% that there is no need to remove anything from
+% \cs{g_galley_restore_running_tl}.
+% \begin{macrocode}
+\tl_new:N \l_galley_justification_other_tl
+% \end{macrocode}
+% \end{variable}
+%
+% The second level four object is the justification, which again
+% takes no arguments.
+% \begin{macrocode}
+\DeclareObjectType { justification } { 0 }
+% \end{macrocode}
+% There are two templates here with the same interface: the standard one
+% to apply from this point onward, and one which applies only to a single
+% paragraph.
+% \begin{macrocode}
+\DeclareTemplateInterface { justification } { std } { 0 }
+ {
+ end-skip : skip = 0 pt plus 1 fil ,
+ fixed-word-spacing : boolean = false ,
+ indent-width : length ,
+ left-skip : skip = 0 pt ,
+ right-skip : skip = 0 pt ,
+ start-skip : skip = 0 pt ,
+ stretch-last-line : boolean = false
+ }
+\DeclareTemplateInterface { justification } { single } { 0 }
+ {
+ end-skip : skip = 0 pt plus 1 fil ,
+ fixed-word-spacing : boolean = false ,
+ indent-width : length ,
+ left-skip : skip = 0 pt ,
+ right-skip : skip = 0 pt ,
+ start-skip : skip = 0 pt ,
+ stretch-last-line : boolean = false
+ }
+% \end{macrocode}
+% \begin{variable}{\l_galley_fixed_spacing_bool}
+% The implementation here is pretty simple as almost everything that
+% goes on is a simple case of saving the settings, which are then
+% applied either by \TeX{} itself or the rest of the galley system.
+% \begin{macrocode}
+\DeclareTemplateCode { justification } { std } { 0 }
+ {
+ end-skip = \l_galley_par_end_skip ,
+ fixed-word-spacing = \l_galley_fixed_spacing_bool ,
+ indent-width = \l_galley_par_indent_dim ,
+ left-skip = \l_galley_line_left_skip ,
+ right-skip = \l_galley_line_right_skip ,
+ start-skip = \l_galley_par_begin_skip ,
+ stretch-last-line = \l_galley_par_stretch_last_bool
+ }
+ {
+ \AssignTemplateKeys
+ \tl_clear:N \l_galley_justification_other_tl
+ \galley_set_interword_spacing:N \l_galley_fixed_spacing_bool
+ \bool_if:NTF \l_galley_par_stretch_last_bool
+ { \int_set_eq:NN \l_galley_last_line_fit_int \c_one_thousand }
+ { \int_zero:N \l_galley_last_line_fit_int }
+ \skip_set:Nn \@rightskip { \l_galley_line_right_skip }
+ }
+% \end{macrocode}
+% \end{variable}
+% To deal with a single paragraph, the approach used is to save the current
+% settings to the paragraph-reset code, then to assign the template in the
+% same way as for the |std| template.
+% \begin{macrocode}
+\DeclareTemplateCode { justification } { single } { 0 }
+ {
+ end-skip = \l_galley_par_end_skip ,
+ fixed-word-spacing = \l_galley_fixed_spacing_bool ,
+ indent-width = \l_galley_par_indent_dim ,
+ left-skip = \l_galley_line_left_skip ,
+ right-skip = \l_galley_line_right_skip ,
+ start-skip = \l_galley_par_begin_skip ,
+ stretch-last-line = \l_galley_par_stretch_last_bool
+ }
+ {
+ \tl_put_left:Nx \l_galley_justification_other_tl
+ {
+ \skip_set:Nn \exp_not:N \l_galley_par_end_skip
+ { \skip_use:N \l_galley_par_end_skip }
+ \bool_if:NTF \l_galley_fixed_spacing_bool
+ { \bool_set_true:N \exp_not:N \l_galley_fixed_spacing_bool }
+ { \bool_set_false:N \exp_not:N \l_galley_fixed_spacing_bool }
+ \galley_set_interword_space:N
+ \exp_not:N \l_galley_fixed_spacing_bool
+ \dim_set:Nn \exp_not:N \l_galley_par_indent_dim
+ { \dim_use:N \l_galley_par_indent_dim }
+ \skip_set:Nn \l_galley_line_left_skip
+ { \skip_use:N \l_galley_line_left_skip }
+ \skip_set:Nn \exp_not:N \l_galley_line_right_skip
+ { \skip_use:N \l_galley_line_right_skip }
+ \skip_set:Nn \exp_not:N \l_galley_par_start_skip
+ { \skip_use:N \l_galley_par_start_skip }
+ \int_set:Nn \exp_not:N \l_galley_last_line_fit_int
+ { \int_use:N \l_galley_last_line_fit_int }
+ \skip_set:Nn \exp_not:N \@rightskip
+ { \skip_use:N \l_galley_line_right_skip }
+ }
+ \tl_gput_right:Nn \g_galley_restore_running_tl
+ { \l_galley_justification_other_tl }
+ \AssignTemplateKeys
+ \galley_set_interword_spacing:N \l_galley_fixed_spacing_bool
+ \bool_if:NTF \l_galley_par_stretch_last_bool
+ { \int_set_eq:NN \l_galley_last_line_fit_int \c_one_thousand }
+ { \int_zero:N \l_galley_last_line_fit_int }
+ \skip_set:Nn \@rightskip { \l_galley_line_right_skip }
+ }
+% \end{macrocode}
+% The standard instance for justification is very simple to set up as
+% the default values for the template are set up for exactly this case.
+% The advantage of this scheme is that at a design level altering the
+% indent used for justified paragraphs is very easy to do. As this is
+% the standard template for all \LaTeX3 documents, it is applied here.
+% \begin{macrocode}
+\DeclareInstance { justification } { justified } { std }
+ { indent-width = 15 pt }
+\UseInstance { justification } { justified }
+% \end{macrocode}
+% The instance for no indentation at all but with justified text is
+% intended for layouts which leave white space between paragraphs. With
+% no indentation, some space has to be included at the end of each
+% paragraph. This is set up to mirror the indent that has been removed.
+% \begin{macrocode}
+\DeclareInstance { justification } { noindent } { std }
+ {
+ end-skip = 15 pt plus 1 fil ,
+ indent-width = 0 pt
+ }
+% \end{macrocode}
+% The other standard justification schemes are for text which is either
+% centred or ragged. The settings here are taken from the \LaTeXe{}
+% \pkg{ragged2e} package, as they maintain a reasonable appearance by
+% ensuring that \TeX{} will not be too tolerant of very short lines.
+% To keep the design clear here, no default values are relied on even
+% though this would make the instance declarations shorter.
+% \begin{macrocode}
+\DeclareInstance { justification } { centered } { std }
+ {
+ end-skip = 0 pt ,
+ fixed-word-spacing = true ,
+ indent-width = 0 pt ,
+ left-skip = 0 pt plus 1 em ,
+ right-skip = 0 pt plus 1 em
+ }
+\DeclareInstance { justification } { ragged-left } { std }
+ {
+ end-skip = 0 pt ,
+ fixed-word-spacing = true ,
+ indent-width = 0 pt ,
+ left-skip = 0 pt plus 2 em ,
+ right-skip = 0 pt
+ }
+\DeclareInstance { justification } { ragged-right } { std }
+ {
+ end-skip = 0 pt plus 1 fil ,
+ fixed-word-spacing = true ,
+ indent-width = 0 pt ,
+ left-skip = 0 pt ,
+ right-skip = 0 pt plus 2 em
+ }
+% \end{macrocode}
+% The \texttt{centering} instance is used to centre material without
+% hyphenation: this is used for centring arbitrary material rather
+% than text.
+% \begin{macrocode}
+\DeclareInstance { justification } { centering } { std }
+ {
+ end-skip = 0 pt ,
+ fixed-word-spacing = true ,
+ indent-width = 0 pt ,
+ left-skip = 0 pt plus 1 fil ,
+ right-skip = 0 pt plus 1 fil
+ }
+% \end{macrocode}
+%
+% \begin{macro}{\galley_justification_first:, \galley_justification_other:}
+% A second form of justification template is the case where the first
+% paragraph is different from all of the others. This is set up by
+% getting the justification to reset itself after the first paragraph.
+% The code built into the \texttt{std} version will ensure that any
+% subsequent template use will over-ride the setting here correctly.
+% \begin{macrocode}
+\DeclareTemplateInterface { justification } { compound } { 0 }
+ {
+ first-paragraph : instance { justification } ,
+ other-paragraphs : instance { justification }
+ }
+\DeclareTemplateCode { justification } { compound } { 0 }
+ {
+ first-paragraph = \galley_justification_first: ,
+ other-paragraphs = \galley_justification_other:
+ }
+ {
+ \AssignTemplateKeys
+ \galley_justification_first:
+ \tl_set:Nn \l_galley_justification_other_tl
+ { \galley_justification_other: }
+ \tl_gput_right:Nn \g_galley_restore_running_tl
+ { \l_galley_justification_other_tl }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% How \TeX{} breaks text into lines is influences by a number of
+% parameters, most of which are not actually likely to change. These
+% work with the \texttt{hyphenation} but are independent of whether
+% any hyphenation is actually active. The math values here could be
+% set up as a separate template, but in practice this seems likely to
+% be overkill.
+% \begin{macrocode}
+\DeclareObjectType { line-breaking } { 0 }
+% \end{macrocode}
+% The only template provided for line breaking is a simple interface to
+% \TeX{}'s parameters. There is not really much that can be added to this:
+% after all, the way that penalties work is more or less arbitrary but
+% works well! The default values given here are intended to be sensible
+% for a lot of cases.
+% \begin{macrocode}
+\DeclareTemplateInterface { line-breaking } { std } { 0 }
+ {
+ badness : integer = 1000 ,
+ binop-penalty : integer = 700 ,
+ double-hyphen-demerits : integer = 10 000 ,
+ emergency-stretch : skip = 0 pt ,
+ final-hyphen-demerits : integer = 5000 ,
+ fuzz : length = 0.1 pt ,
+ line-penalty : integer = 10 ,
+ mismatch-demerits : integer = 10 000 ,
+ pretolerance : integer = 100 ,
+ relation-penalty : integer = 500 ,
+ tolerance : integer = 200
+ }
+\DeclareTemplateCode{ line-breaking } { std } { 0 }
+ {
+ badness = \l_galley_linebreak_badness_int ,
+ binop-penalty = \l_galley_binop_penalty_int ,
+ double-hyphen-demerits = \l_galley_double_hyphen_demerits_int ,
+ emergency-stretch = \l_galley_emergency_stretch_skip ,
+ final-hyphen-demerits = \l_galley_final_hyphen_demerits_int ,
+ fuzz = \l_galley_linebreak_fuzz_dim ,
+ line-penalty = \l_galley_linebreak_penalty_int ,
+ mismatch-demerits = \l_galley_mismatch_demerits_int ,
+ pretolerance = \l_galley_linebreak_pretolerance_int ,
+ relation-penalty = \l_galley_relation_penalty_int ,
+ tolerance = \l_galley_linebreak_tolerance_int
+ }
+ { \AssignTemplateKeys }
+% \end{macrocode}
+% The default values are set such that they are suitable for good
+% quality typesetting. So the standard template changes nothing at
+% all from the template. This instance should also be applied now,
+% as it will then apply to the entire document unless changed
+% deliberately.
+% \begin{macrocode}
+\DeclareInstance { line-breaking } { std } { std } { }
+\UseInstance { line-breaking } { std }
+% \end{macrocode}
+%
+% \subsection{Between paragraphs}
+%
+% \begin{variable}
+% {
+% \l_galley_club_penalty_int ,
+% \l_galley_display_club_penalty_int ,
+% \l_galley_display_widow_penalty_int ,
+% \l_galley_interline_penalty_int ,
+% \l_galley_widow_penalty_int
+% }
+% The second object here sets up how \TeX{} acts to break paragraphs at
+% page boundaries. As with the \texttt{line-breaking} object, there is not
+% much to do except provide an interface to the \TeX{} internals. The
+% \texttt{std} template does \emph{not} make the \eTeX{} array nature of
+% various penalties available.
+% \begin{macrocode}
+\DeclareObjectType { paragraph-breaking } { 0 }
+\DeclareTemplateInterface { paragraph-breaking } { std } { 0 }
+ {
+ badness : integer = 1000 ,
+ broken-penalty : integer = 100 ,
+ club-penalty : integer = 150 ,
+ display-club-penalty : integer = 150 ,
+ display-widow-penalty : integer = 150 ,
+ fuzz : length = 0.1 pt ,
+ interline-penalty : integer = 0 ,
+ post-display-penalty : integer = 0 ,
+ pre-display-penalty : integer = 10 000 ,
+ widow-penalty : integer = 150
+ }
+\DeclareTemplateCode { paragraph-breaking } { std } { 0 }
+ {
+ badness = \l_galley_parbreak_badness_int ,
+ broken-penalty = \l_galley_broken_penalty_int ,
+ club-penalty = \l_galley_club_penalty_int ,
+ display-club-penalty = \l_galley_display_club_penalty_int ,
+ display-widow-penalty = \l_galley_display_widow_penalty_int ,
+ fuzz = \l_galley_parbreak_fuzz_dim ,
+ interline-penalty = \l_galley_interline_penalty_int ,
+ post-display-penalty = \l_galley_post_display_penalty_int ,
+ pre-display-penalty = \l_galley_pre_display_penalty_int ,
+ widow-penalty = \l_galley_widow_penalty_int
+ }
+ {
+ \AssignTemplateKeys
+ \galley_set_club_penalties:V \l_galley_club_penalty_int
+ \galley_set_display_club_penalties:V \l_galley_display_club_penalty_int
+ \galley_set_display_widow_penalties:V \l_galley_display_widow_penalty_int
+ \galley_set_interline_penalty:n \l_galley_interline_penalty_int
+ \galley_set_widow_penalties:V \l_galley_widow_penalty_int
+ }
+% \end{macrocode}
+% \end{variable}
+% The standard instance of the \texttt{paragraph-breaking} object simply
+% applies the defaults: this is used.
+% \begin{macrocode}
+\DeclareInstance { paragraph-breaking } { std } { std } { }
+\UseInstance { paragraph-breaking } { std }
+% \end{macrocode}
+% Two additional instances are provided: one to prevent any breaks
+% at all, and a second to prevent any widow or club lines.
+% \begin{macrocode}
+\DeclareInstance { paragraph-breaking } { nobreak } { std }
+ {
+ interline-penalty = 10 000 ,
+ post-display-penalty = 10 000
+ }
+\DeclareInstance { paragraph-breaking } { nolone } { std }
+ {
+ club-penalty = 10 000 ,
+ display-club-penalty = 10 000 ,
+ display-widow-penalty = 10 000 ,
+ widow-penalty = 10 000
+ }
+% \end{macrocode}
+% \begin{variable}
+% {
+% \l_galley_parbreak_badness_tl ,
+% \l_galley_broken_penalty_tl ,
+% \l_galley_club_penalties_tl ,
+% \l_galley_display_club_penalties_tl ,
+% \l_galley_display_widow_penalties_tl ,
+% \l_galley_parbreak_fuzz_tl ,
+% \l_galley_interline_penalty_tl ,
+% \l_galley_post_display_penalty_tl ,
+% \l_galley_pre_display_penalty_tl ,
+% \l_galley_widow_penalties_tl ,
+% \c_galley_parbreak_multi_seq ,
+% \c_galley_parbreak_single_seq
+% }
+% There is also a version of this code which applies only to one
+% paragraph. This is done by storing the input in token list variables
+% with no default: only explicit settings will be picked up.
+% \begin{macrocode}
+\DeclareTemplateInterface { paragraph-breaking } { single } { 0 }
+ {
+ badness : tokenlist ,
+ broken-penalty : tokenlist ,
+ club-penalty : tokenlist ,
+ display-club-penalty : tokenlist ,
+ display-widow-penalty : tokenlist ,
+ fuzz : tokenlist ,
+ interline-penalty : tokenlist ,
+ post-display-penalty : tokenlist ,
+ pre-display-penalty : tokenlist ,
+ widow-penalty : tokenlist
+ }
+\DeclareTemplateCode { paragraph-breaking } { single } { 0 }
+ {
+ badness = \l_galley_parbreak_badness_tl ,
+ broken-penalty = \l_galley_broken_penalty_tl ,
+ club-penalty = \l_galley_club_penalties_tl ,
+ display-club-penalty = \l_galley_display_club_penalties_tl ,
+ display-widow-penalty = \l_galley_display_widow_penalties_tl ,
+ fuzz = \l_galley_parbreak_fuzz_tl ,
+ interline-penalty = \l_galley_interline_penalty_tl ,
+ post-display-penalty = \l_galley_post_display_penalty_tl ,
+ pre-display-penalty = \l_galley_pre_display_penalty_tl ,
+ widow-penalty = \l_galley_widow_penalties_tl
+ }
+ {
+ \AssignTemplateKeys
+% \end{macrocode}
+% The fuzz and interline penalties are handled explicitly as they have
+% particular requirements.
+% \begin{macrocode}
+ \tl_if_empty:NF \l_galley_interline_penalty_tl
+ {
+ \tl_gput_right:Nx \g_galley_par_after_hook_tl
+ {
+ \int_set:Nn \exp_not:N \l_galley_interline_penalty_int
+ { \galley_interline_penalty: }
+ }
+ \int_set:Nn \l_galley_interline_penalty_int
+ { \l_galley_interline_penalty_tl }
+ }
+ \tl_if_empty:NF \l_galley_parbreak_fuzz_tl
+ {
+ \tl_gput_right:Nx \g_galley_par_after_hook_tl
+ {
+ \dim_set:Nn \exp_not:N \l_galley_parbreak_fuzz_dim
+ { \dim_use:N \l_galley_parbreak_fuzz_dim }
+ }
+ \dim_set:Nn \l_galley_parbreak_fuzz_dim { \l_galley_parbreak_fuzz_tl }
+ }
+% \end{macrocode}
+% For the single integer penalties, a simple check is needed to save the
+% value.
+% \begin{macrocode}
+ \seq_map_inline:Nn \c_galley_parbreak_single_seq
+ {
+ \tl_if_empty:cF { l_galley_ ##1 _tl }
+ {
+ \tl_gput_right:Nx \g_galley_par_after_hook_tl
+ {
+ \int_set:Nn \exp_not:c { l_galley_ ##1 _int }
+ { \int_use:c { l_galley_ ##1 _int } }
+ }
+ \int_set:cn { l_galley_ ##1 _int }
+ { \tl_use:c { l_galley_ ##1 _tl } }
+ }
+ }
+% \end{macrocode}
+% A bit more complex for the array penalties. Although the interface here
+% does not expose the arrays, it is necessary to correctly save them.
+% \begin{macrocode}
+ \seq_map_inline:Nn \c_galley_parbreak_multi_seq
+ {
+ \tl_if_empty:cF { l_galley_ ##1 _tl }
+ {
+ \use:c { galley_save_ ##1 :N } \l_galley_tmpa_clist
+ \tl_gput_right:Nx \g_galley_par_after_hook_tl
+ {
+ \exp_not:c { galley_set_ ##1 :n }
+ { \exp_not:o \l_galley_tmpa_clist }
+ }
+ \use:c { galley_set_ ##1 :v } { l_galley_ ##1 _tl }
+ }
+ }
+ }
+\seq_new:N \c_galley_parbreak_multi_seq
+\seq_gput_right:Nn \c_galley_parbreak_multi_seq { club_penalties }
+\seq_gput_right:Nn \c_galley_parbreak_multi_seq { display_club_penalties }
+\seq_gput_right:Nn \c_galley_parbreak_multi_seq { display_widow_penalties }
+\seq_gput_right:Nn \c_galley_parbreak_multi_seq { widow_penalties }
+\seq_new:N \c_galley_parbreak_single_seq
+\seq_gput_right:Nn \c_galley_parbreak_single_seq { parbreak_badness }
+\seq_gput_right:Nn \c_galley_parbreak_single_seq { broken_penalty }
+\seq_gput_right:Nn \c_galley_parbreak_single_seq { post_display_penalty }
+\seq_gput_right:Nn \c_galley_parbreak_single_seq { pre_display_penalty }
+% \end{macrocode}
+% \end{variable}
+% \begin{macrocode}
+\DeclareInstance { paragraph-breaking } { single-std } { single } { }
+\DeclareInstance { paragraph-breaking } { single-nobreak } { single }
+ {
+ interline-penalty = 10 000 ,
+ post-display-penalty = 10 000
+ }
+\DeclareInstance { paragraph-breaking } { single-noclub } { single }
+ {
+ club-penalty = 10 000 ,
+ display-club-penalty = 10 000
+ }
+\DeclareInstance { paragraph-breaking } { single-nolone } { single }
+ {
+ club-penalty = 10 000 ,
+ display-club-penalty = 10 000 ,
+ display-widow-penalty = 10 000 ,
+ widow-penalty = 10 000
+ }
+\DeclareInstance { paragraph-breaking } { single-nowidow } { single }
+ {
+ display-widow-penalty = 10 000 ,
+ widow-penalty = 10 000
+ }
+% \end{macrocode}
+%
+% \subsection{Templates for display material}
+%
+% To allow special handling of display-like material, templates are
+% needed at the beginning and end of the block which set up any special
+% space or breaks. These need to be optional, and so are stored as token
+% lists: rather than \enquote{magic} values, empty lists indicate that
+% standard settings are to be used. To ensure that the error checking
+% needed takes place early, each token list is re-set with the
+% appropriate evaluation.
+% \begin{macrocode}
+\DeclareObjectType { display-begin } { 0 }
+\DeclareObjectType { display-end } { 0 }
+\DeclareTemplateInterface { display-begin } { std } { 0 }
+ {
+ par-penalty : tokenlist ,
+ par-space : tokenlist ,
+ penalty : tokenlist ,
+ space : tokenlist
+ }
+\DeclareTemplateInterface { display-end } { std } { 0 }
+ {
+ par-penalty : tokenlist ,
+ par-space : tokenlist ,
+ penalty : tokenlist ,
+ space : tokenlist
+ }
+\DeclareTemplateCode { display-begin } { std } { 0 }
+ {
+ par-penalty = \l_galley_display_begin_par_vpenalty_tl ,
+ par-space = \l_galley_display_begin_par_vspace_tl ,
+ penalty = \l_galley_display_begin_vpenalty_tl ,
+ space = \l_galley_display_begin_vspace_tl
+ }
+ {
+ \AssignTemplateKeys
+ \tl_if_empty:NF \l_galley_display_begin_par_vpenalty_tl
+ {
+ \tl_set:Nx \l_galley_display_begin_par_vpenalty_tl
+ { \int_eval:n { \l_galley_display_begin_par_vpenalty_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_begin_par_vspace_tl
+ {
+ \tl_set:Nx \l_galley_display_begin_par_vspace_tl
+ { \skip_eval:n { \l_galley_display_begin_par_vspace_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_begin_vpenalty_tl
+ {
+ \tl_set:Nx \l_galley_display_begin_vpenalty_tl
+ { \int_eval:n { \l_galley_display_begin_vpenalty_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_begin_vspace_tl
+ {
+ \tl_set:Nx \l_galley_display_begin_vspace_tl
+ { \skip_eval:n { \l_galley_display_begin_vspace_tl } }
+ }
+ }
+\DeclareTemplateCode { display-end } { std } { 0 }
+ {
+ par-penalty = \l_galley_display_end_par_vpenalty_tl ,
+ par-space = \l_galley_display_end_par_vspace_tl ,
+ penalty = \l_galley_display_end_vpenalty_tl ,
+ space = \l_galley_display_end_vspace_tl
+ }
+ {
+ \AssignTemplateKeys
+ \tl_if_empty:NF \l_galley_display_end_par_vpenalty_tl
+ {
+ \tl_set:Nx \l_galley_display_end_par_vpenalty_tl
+ { \int_eval:n { \l_galley_display_end_par_vpenalty_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_end_par_vspace_tl
+ {
+ \tl_set:Nx \l_galley_display_end_par_vspace_tl
+ { \skip_eval:n { \l_galley_display_end_par_vspace_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_end_vpenalty_tl
+ {
+ \tl_set:Nx \l_galley_display_end_vpenalty_tl
+ { \int_eval:n { \l_galley_display_end_vpenalty_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_end_vspace_tl
+ {
+ \tl_set:Nx \l_galley_display_end_vspace_tl
+ { \skip_eval:n { \l_galley_display_end_vspace_tl } }
+ }
+ }
+% \end{macrocode}
+%
+% \subsection{\LaTeXe{} functions}
+%
+% \begin{macro}{\nobreak}
+% \begin{macro}{\noindent}
+% \begin{macro}{\vspace}
+% In package mode, some of \LaTeXe{}'s functions are re-implemented using
+% the galley system. Not all of the optional arguments currently work!
+% \begin{macrocode}
+\RenewDocumentCommand \nobreak { }
+ { \bool_gset_true:N \g_galley_no_break_next_bool }
+\RenewDocumentCommand \noindent { }
+ { \bool_gset_false:N \g_galley_omit_next_indent_bool }
+\RenewDocumentCommand \vspace { s m } { \galley_set_vspace_user:n {#2} }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.ins b/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.ins
new file mode 100644
index 00000000000..cadc1d2a98f
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/xgalley/xgalley.ins
@@ -0,0 +1,41 @@
+\iffalse meta-comment
+
+File xgalley.ins Copyright (C) 2010,2011 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 released version of this bundle is available from CTAN.
+
+\fi
+
+\input docstrip.tex
+\askforoverwritefalse
+
+\preamble
+
+EXPERIMENTAL CODE
+
+Do not distribute this file without also distributing the
+source files specified above.
+
+Do not distribute a modified version of this file.
+
+\endpreamble
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+
+\keepsilent
+
+\generate{\file{l3galley.sty}{\from{l3galley.dtx}{package}}}
+\generate{\file{xgalley.sty} {\from{xgalley.dtx} {package}}}
+
+\endbatchfile
diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty
new file mode 100644
index 00000000000..29045fcdea9
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex-trace.sty
@@ -0,0 +1,1637 @@
+%%
+%% This is file `l3regex-trace.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% l3regex.dtx (with options: `package,trace')
+%%
+%% EXPERIMENTAL CODE
+%%
+%% Do not distribute this file without also distributing the
+%% source files specified above.
+%%
+%% Do not distribute a modified version of this file.
+%%
+%% File: l3regex.dtx Copyright (C) 2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX3 Project.
+%%
+%% -----------------------------------------------------------------------
+\RequirePackage{expl3}
+\GetIdInfo$Id: l3regex.dtx 2895 2011-10-09 15:58:19Z joseph $
+ {L3 Experimental Regular Expressions}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\RequirePackage{l3str}
+\cs_new:Npn \regex_tmp:w { }
+\tl_new:N \g_regex_tmpa_tl
+\tl_new:N \l_regex_tmpa_tl
+\tl_new:N \l_regex_tmpb_tl
+\int_new:N \l_regex_tmpa_int
+\tl_new:N \l_regex_pattern_str
+\int_new:N \l_regex_max_state_int
+\int_new:N \l_regex_left_state_int
+\int_new:N \l_regex_right_state_int
+\seq_new:N \l_regex_left_state_seq
+\seq_new:N \l_regex_right_state_seq
+\int_new:N \l_regex_capturing_group_int
+\seq_new:N \l_regex_capturing_group_seq
+\tl_new:N \l_regex_one_or_group_tl
+\int_new:N \l_regex_repetition_int
+\bool_new:N \l_regex_look_behind_bool
+\tl_new:N \l_regex_look_behind_str
+\cs_new_eq:NN \regex_build_tmp_class:n \use_none:n
+\bool_new:N \l_regex_class_bool
+\tl_new:N \l_regex_class_tl
+\tl_const:Nn \c_regex_d_tl
+ {
+ \regex_item_range:nn {48} {57} % 0--9
+ }
+\tl_const:Nn \c_regex_D_tl
+ {
+ \regex_item_more:n {57} % 9
+ \regex_item_range:nn {0} {47} % 0
+ }
+\tl_const:Nn \c_regex_h_tl
+ {
+ \regex_item_equal:n {32} % space
+ \regex_item_equal:n {9} % tab
+ }
+\tl_const:Nn \c_regex_H_tl
+ {
+ \regex_item_neq:n {32} % space
+ \regex_item_neq:n {9} % tab
+ \regex_break_true:w
+ }
+\tl_const:Nn \c_regex_s_tl
+ {
+ \regex_item_equal:n {32} % space
+ \regex_item_neq:n {11} % vtab
+ \regex_item_range:nn {9} {13} % tab, lf, vtab, ff, cr
+ }
+\tl_const:Nn \c_regex_S_tl
+ {
+ \regex_item_more:n {32} % > space
+ \regex_item_range:nn {14} {31} % tab < ... < space
+ \regex_item_range:nn {0} {8} % < tab
+ \regex_item_equal:n {11} % vtab
+ }
+\tl_const:Nn \c_regex_v_tl
+ {
+ \regex_item_range:nn {10} {13} % lf, vtab, ff, cr
+ }
+\tl_const:Nn \c_regex_V_tl
+ {
+ \regex_item_more:n {13} % cr
+ \regex_item_range:nn {0} {9} % < lf
+ }
+\tl_const:Nn \c_regex_w_tl
+ {
+ \regex_item_range:nn {97} {122} % a--z
+ \regex_item_range:nn {65} {90} % A--Z
+ \regex_item_range:nn {48} {57} % 0--9
+ \regex_item_equal:n {95} % _
+ }
+\tl_const:Nn \c_regex_W_tl
+ {
+ \regex_item_range:nn {0} {47} % <`0
+ \regex_item_range:nn {58} {64} % (`9+1)--(`A-1)
+ \regex_item_range:nn {91} {94} % (`Z+1)--(`_-1)
+ \regex_item_equal:n {96} % `
+ \regex_item_more:n {122} % z
+ }
+\tl_const:Nn \c_regex_N_tl
+ {
+ \regex_item_neq:n {10} % lf
+ \regex_break_true:w
+ }
+\tl_new:N \l_regex_query_str
+\int_new:N \l_regex_start_step_int
+\int_new:N \l_regex_current_char_int
+\int_new:N \l_regex_current_step_int
+\int_new:N \l_regex_unique_step_int
+\int_new:N \l_regex_current_state_int
+\prop_new:N \l_regex_current_submatches_prop
+\int_new:N \l_regex_max_index_int
+\tl_new:N \l_regex_every_match_tl
+\cs_new_protected:Npn \regex_last_match_empty_no:F #1 {#1}
+\cs_new_protected:Npn \regex_last_match_empty_yes:F
+ { \int_compare:nNnF \l_regex_start_step_int = \l_regex_current_step_int }
+\cs_new_eq:NN \regex_last_match_empty:F \regex_last_match_empty_no:F
+\bool_new:N \l_regex_success_bool
+\bool_new:N \l_regex_success_empty_bool
+\int_new:N \l_regex_success_step_int
+\prop_new:N \l_regex_success_submatches_prop
+\bool_new:N \l_regex_fresh_thread_bool
+\seq_new:N \g_regex_submatches_seq
+\int_new:N \g_regex_match_count_int
+\seq_new:N \g_regex_split_seq
+\tl_new:N \l_regex_replacement_tl
+\tl_new:N \g_regex_replaced_str
+\cs_new_eq:NN \s_regex_toks \scan_stop:
+\cs_new_protected:Npn \regex_toks_put_left:Nx #1#2
+ {
+ \cs_set_nopar:Npx \regex_tmp:w \s_regex_toks { \s_regex_toks #2 }
+ \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
+ { \exp_after:wN \regex_tmp:w \tex_the:D \tex_toks:D #1 }
+ }
+\cs_new_protected:Npn \regex_toks_put_right:Nx #1#2
+ {
+ \cs_set_nopar:Npx \regex_tmp:w {#2}
+ \tex_toks:D #1 \exp_after:wN
+ { \tex_the:D \tex_toks:D \exp_after:wN #1 \regex_tmp:w }
+ }
+\cs_new_eq:NN \regex_if_tail_stop:N \quark_if_recursion_tail_stop:N
+\cs_new_protected_nopar:Npn \regex_if_tail_error:Nn #1#2
+ { \quark_if_recursion_tail_stop_do:Nn #1 { \regex_build_error:n {#2} } }
+\cs_new_protected_nopar:Npn \regex_build_error:n #1
+ {
+ \msg_error:nnxx { regex } { build-error } {\int_eval:n{#1}}
+ {
+ \prg_case_int:nnn {#1}
+ {
+ {-999} {File~not~found}
+ {-998} {Unsupported~construct}
+ {-997} {The~regular~expression~is~too~large~(32768~states).}
+ {1} {\iow_char:N\\~at~end~of~pattern }
+ {4} {Numbers~out~of~order~in~\iow_char:N\{\iow_char\}~quantifier.}
+ {6} {Missing~terminating~\iow_char:N\]~for~character~class }
+ {7} {Invalid~escape~sequence~in~character~class}
+ {8} {Range~out~of~order~in~character~class}
+ {22} {Mismatched~parentheses}
+ {34} {Character~value~in~\iow_char:N\\x{...}~sequence~is~too~large}
+ }
+ { Internal~bug. }
+ }
+ }
+\msg_new:nnn { regex } { build-error } { (error~#1): ~ #2 }
+\cs_new_nopar:Npn \regex_break_true:w #1 \regex_break_point:TF #2 #3 {#2}
+\cs_new_nopar:Npn \regex_break_false:w #1 \regex_break_point:TF #2 #3 {#3}
+\cs_new_eq:NN \regex_break_point:TF \use_ii:nn
+\cs_new_nopar:Npn \regex_item_equal:n #1
+ {
+ \if_num:w #1 = \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_range:nn #1 #2
+ {
+ \reverse_if:N \if_num:w #1 > \l_regex_current_char_int
+ \reverse_if:N \if_num:w #2 < \l_regex_current_char_int
+ \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w
+ \fi:
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_less:n #1
+ {
+ \if_num:w #1 > \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_more:n #1
+ {
+ \if_num:w #1 < \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_neq:n #1
+ {
+ \if_num:w #1 = \l_regex_current_char_int
+ \exp_after:wN \regex_break_false:w
+ \fi:
+ }
+\cs_new_protected:Npn \regex_get_digits:nw #1
+ {
+ \tex_afterassignment:D \regex_tmp:w
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \exp_not:n {#1}
+ { \if_false: } } \fi:
+ \regex_get_digits_aux:N
+ }
+\cs_new_nopar:Npn \regex_get_digits_aux:N #1
+ {
+ \if_num:w 9 < 1 \exp_not:N #1 \exp_stop_f:
+ \else:
+ \if_charcode:w \c_space_token \exp_not:N #1
+ \else:
+ \regex_get_digits_end:w
+ \fi:
+ \fi:
+ #1 \regex_get_digits_aux:N
+ }
+\cs_new_nopar:Npn \regex_get_digits_end:w
+ \fi: \fi: #1 \regex_get_digits_aux:N
+ {
+ \fi: \fi:
+ \if_false: { { \fi: } }
+ #1
+ }
+\prg_new_conditional:Npnn \regex_aux_char_if_special:N #1 { TF }
+ {
+ \if_num:w `#1 < 97 \exp_stop_f:
+ \if_num:w `#1 < 58 \exp_stop_f:
+ \if_num:w \int_eval:w (`#1 - \c_eight)/\c_sixteen = \c_two
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w `#1 / 26 = \c_three
+ \prg_return_false:
+ \else:
+ \prg_return_true:
+ \fi:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w `#1 / \c_five = 25 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \fi:
+ }
+\prg_new_conditional:Npnn \regex_aux_char_if_alphanumeric:N #1 { TF }
+ {
+ \if_num:w `#1 < 91 \exp_stop_f:
+ \if_num:w `#1 < 65 \exp_stop_f:
+ \if_num:w \c_nine < 1 #1 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \else:
+ \prg_return_true:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w (`#1-\c_six)/26 = \c_four
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \regex_build_new_state:
+ {
+ \int_compare:nNnTF \l_regex_max_state_int > {32766}
+ { \regex_build_error:n {-997} }
+ {
+ \int_incr:N \l_regex_max_state_int
+ \tex_toks:D \l_regex_max_state_int { \s_regex_toks }
+ }
+ \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_right_state_int \l_regex_max_state_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_transition_aux:NN #1#2
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ { #1 { \int_use:N #2 } }
+ }
+\cs_new_protected_nopar:Npn \regex_build_transitions_aux:NNNN #1#2#3#4
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ #1 { \int_use:N #2 }
+ #3 { \int_use:N #4 }
+ }
+ }
+\cs_new_protected:Npn \regex_build:n #1
+ {
+ \regex_build_setup:
+ \str_aux_escape:NNNn
+ \regex_build_i_unescaped:N
+ \regex_build_i_escaped:N
+ \regex_build_i_raw:N
+ { #1 }
+ \regex_build_open_aux:
+ \g_str_result_tl \prg_do_nothing: \prg_do_nothing:
+ \seq_push:Nn \l_regex_capturing_group_seq { 0 }
+ \regex_build_close_aux: \regex_build_group_:
+ \regex_build_end:
+ }
+\cs_new_nopar:Npn \regex_build_i_unescaped:N #1
+ {
+ \regex_aux_char_if_special:NTF #1
+ { \exp_not:N \regex_build_control:N #1 }
+ { \exp_not:N \regex_build_raw:N #1 }
+ }
+\cs_new_nopar:Npn \regex_build_i_escaped:N #1
+ {
+ \regex_aux_char_if_alphanumeric:NTF #1
+ { \exp_not:N \regex_build_control:N #1 }
+ { \exp_not:N \regex_build_raw:N #1 }
+ }
+\cs_new_nopar:Npn \regex_build_i_raw:N #1
+ { \exp_not:N \regex_build_raw:N #1 }
+\cs_new_protected_nopar:Npn \regex_build_default_control:N #1
+ {
+ \cs_if_exist_use:cF { regex_build_#1: }
+ { \regex_build_default_raw:N #1 }
+ }
+\cs_new_protected_nopar:Npn \regex_build_setup:
+ {
+ \cs_set_eq:NN \regex_build_control:N \regex_build_default_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_build_default_raw:N
+ \int_set_eq:NN \l_regex_capturing_group_int \c_zero
+ \int_zero:N \l_regex_left_state_int
+ \int_zero:N \l_regex_right_state_int
+ \int_zero:N \l_regex_max_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_action_start_wildcard:nn
+ { \int_use:N \l_regex_left_state_int }
+ { \int_use:N \l_regex_right_state_int }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_end:
+ {
+ \seq_if_empty:NF \l_regex_capturing_group_seq
+ {
+ \regex_build_error:n {22}
+ \prg_replicate:nn
+ { \seq_length:N \l_regex_capturing_group_seq } % (
+ { \regex_build_close_aux: \regex_build_group_: }
+ }
+ \regex_toks_put_right:Nx \l_regex_right_state_int
+ { \regex_action_success: }
+ }
+\cs_new_protected_nopar:cpn { regex_build_^: }
+ { \regex_build_anchor_start:N \c_zero }
+\cs_new_protected_nopar:Npn \regex_build_A:
+ { \regex_build_anchor_start:N \c_zero }
+\cs_new_protected_nopar:Npn \regex_build_G:
+ { \regex_build_anchor_start:N \l_regex_start_step_int }
+\cs_new_protected_nopar:Npn \regex_build_anchor_start:N #1
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \int_compare:nNnT {#1} = \l_regex_current_step_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_$: } % $
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \int_compare:nNnT
+ \c_minus_one = \l_regex_current_char_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+\cs_new_eq:Nc \regex_build_Z: { regex_build_$: } %$
+\cs_new_eq:Nc \regex_build_z: { regex_build_$: } %$
+\cs_new_protected_nopar:Npn \regex_build_b:
+ {
+ \bool_set_true:N \l_regex_look_behind_bool
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \regex_if_word_boundary:TF
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ { }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_B:
+ {
+ \bool_set_true:N \l_regex_look_behind_bool
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \regex_if_word_boundary:TF
+ { }
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_if_word_boundary:TF
+ {
+ \tl_if_empty:NTF \l_regex_look_behind_str
+ { \c_regex_w_tl }
+ {
+ \group_begin:
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \int_set:Nn \l_regex_current_char_int
+ { ` \str_head:N \l_regex_look_behind_str }
+ }
+ \regex_tmp:w
+ \c_regex_w_tl
+ \regex_break_point:TF
+ { \group_end: \c_regex_W_tl }
+ { \group_end: \c_regex_w_tl }
+ }
+ \regex_break_point:TF
+ }
+\cs_new_protected_nopar:Npn \regex_build_default_raw:N #1
+ {
+ \cs_set:Npx \regex_build_tmp_class:n ##1
+ {
+ \exp_not:n { \exp_not:N \if_num:w }
+ \int_value:w `#1 = \l_regex_current_char_int
+ \regex_action_cost:n { ##1 }
+ \exp_not:n { \exp_not:N \fi: }
+ }
+ \regex_build_one_quantifier:
+ }
+\cs_new_protected_nopar:cpn { regex_build_.: }
+ {
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:N \if_num:w \c_minus_one < \l_regex_current_char_int
+ \regex_action_cost:n {##1}
+ \exp_not:N \fi:
+ }
+ \regex_build_one_quantifier:
+ }
+\cs_new_protected_nopar:Npn \regex_build_char_type:N #1
+ {
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:N #1
+ \exp_not:N \regex_break_point:TF
+ { \regex_action_cost:n {##1} }
+ { }
+ }
+ \regex_build_one_quantifier:
+ }
+\tl_map_inline:nn { dDhHsSvVwWN }
+ {
+ \cs_new_protected_nopar:cpx { regex_build_#1: }
+ {
+ \exp_not:N \regex_build_char_type:N
+ \exp_not:c { c_regex_#1_tl }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_[: }
+ {
+ \tl_clear:N \l_regex_class_tl
+ \cs_set_eq:NN \regex_build_control:N \regex_class_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_class_raw:N
+ \regex_class_first:NN
+ }
+\cs_new_protected_nopar:Npn \regex_class_control:N #1
+ {
+ \cs_if_exist_use:cF { regex_class_#1: }
+ { \regex_class_raw:N #1 }
+ }
+\cs_new_protected_nopar:cpn { regex_class_]: }
+ {
+ \tl_if_empty:NTF \l_regex_class_tl %[
+ { \regex_class_raw:N ] }
+ {
+ \cs_set_eq:NN \regex_build_control:N \regex_build_default_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_build_default_raw:N
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:o \l_regex_class_tl
+ \bool_if:NTF \l_regex_class_bool
+ {
+ \exp_not:N \regex_break_point:TF
+ { \regex_action_cost:n {##1} }
+ { }
+ }
+ {
+ \exp_not:N \regex_break_point:TF
+ { }
+ { \regex_action_cost:n {##1} }
+ }
+ }
+ \regex_build_one_quantifier:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_class_first:NN #1#2
+ {
+ \str_if_eq:nnTF {#1#2} { \regex_build_control:N ^ }
+ { \bool_set_false:N \l_regex_class_bool }
+ {
+ \bool_set_true:N \l_regex_class_bool
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_class_raw:N #1#2#3
+ {
+ \str_if_eq:nnTF {#2#3} { \regex_build_control:N - }
+ { \regex_class_range:Nw #1 }
+ {
+ \regex_class_single:N #1
+ #2 #3
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_class_single:N #1
+ {
+ \tl_put_right:Nx \l_regex_class_tl
+ { \exp_not:N \regex_item_equal:n { \int_value:w `#1 } }
+ }
+\cs_new_protected_nopar:Npn \regex_class_range:Nw #1#2#3
+ {
+ \token_if_eq_meaning:NNTF #2 \regex_build_control:N
+ {
+ \cs_if_exist:cTF { regex_class_#3: }
+ {
+ \regex_class_single:N #1
+ \regex_class_single:N -
+ #2#3
+ }
+ { \regex_class_range_put:NN #1#3 }
+ }
+ { \regex_class_range_put:NN #1#3 }
+ }
+\cs_new_protected_nopar:Npn \regex_class_range_put:NN #1#2
+ {
+ \if_num:w `#1 > `#2 \exp_stop_f:
+ \regex_build_error:n {8}
+ \else:
+ \tl_put_right:Nx \l_regex_class_tl
+ {
+ \if_num:w `#1 = `#2 \exp_stop_f:
+ \exp_not:N \regex_item_equal:n
+ \else:
+ \exp_not:N \regex_item_range:nn { \int_value:w `#1 }
+ \fi:
+ { \int_value:w `#2 }
+ }
+ \fi:
+ }
+\tl_map_inline:nn { dDhHsSvVwWN }
+ {
+ \cs_new_protected_nopar:cpx { regex_class_#1: }
+ {
+ \tl_put_right:Nn \exp_not:N \l_regex_class_tl
+ { \exp_not:c { c_regex_#1_tl } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_quantifier:w #1#2
+ {
+ \token_if_eq_meaning:NNTF #1 \regex_build_control:N
+ {
+ \cs_if_exist_use:cF { regex_build_quantifier_#2:w }
+ {
+ \regex_build_quantifier_end:n { }
+ #1 #2
+ }
+ }
+ {
+ \regex_build_quantifier_end:n { }
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_?:w }
+ { \regex_build_quantifier_aux:nnNN { } { ? } }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_*:w }
+ { \regex_build_quantifier_aux:nnNN { } { * } }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_+:w }
+ { \regex_build_quantifier_aux:nnNN { } { + } }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_aux:nnNN #1#2#3#4
+ {
+ \str_if_eq:nnTF { #3 #4 } { \regex_build_control:N ? }
+ { \regex_build_quantifier_end:n { #2 #4 } #1 }
+ {
+ \regex_build_quantifier_end:n { #2 } #1
+ #3 #4
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_ \c_lbrace_str :w }
+ { \regex_get_digits:nw { \regex_build_quantifier_lbrace:n } }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_lbrace:n #1
+ {
+ \tl_if_empty:nTF {#1}
+ {
+ \regex_build_quantifier_end:n { }
+ \exp_after:wN \regex_build_raw:N \c_lbrace_str
+ }
+ { \regex_build_quantifier_lbrace:nw {#1} }
+ }
+\cs_new_protected_nopar:Npx \regex_build_quantifier_lbrace:nw #1#2#3
+ {
+ \exp_not:N \prg_case_str:nnn { #2 #3 }
+ {
+ { \exp_not:N \regex_build_control:N , }
+ {
+ \exp_not:N \regex_get_digits:nw
+ { \exp_not:N \regex_build_quantifier_lbrace:nnw {#1} }
+ }
+ { \exp_not:N \regex_build_control:N \c_rbrace_str }
+ { \exp_not:N \regex_build_quantifier_end:n {n} {#1} }
+ }
+ {
+ \exp_not:N \regex_build_quantifier_end:n { }
+ \exp_not:N \regex_build_raw:N \c_lbrace_str #1#2
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_lbrace:nnw #1#2#3
+ {
+ \str_if_eq:xxTF { \exp_not:N #3 } { \c_rbrace_str }
+ {
+ \tl_if_empty:nTF {#2}
+ { \regex_build_quantifier_aux:nnN { {#1} {\c_max_int} } {nn} }
+ {
+ \int_compare:nNnT {#1} > {#2}
+ { \regex_build_error:n {4} }
+ \regex_build_quantifier_aux:nnN { {#1} {#2} } {nn}
+ }
+ }
+ {
+ \regex_build_quantifier_end:n { }
+ \use:x
+ {
+ \exp_not:n { \exp_args:No \tl_map_function:nN }
+ { \c_lbrace_str #1 #2 , }
+ \regex_build_raw:N
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_end:n #1
+ { \use:c { regex_build_ \l_regex_one_or_group_tl _ #1 : } }
+\cs_new_protected_nopar:Npn \regex_build_one_quantifier:
+ {
+ \tl_set:Nx \l_regex_one_or_group_tl { one }
+ \regex_build_quantifier:w
+ }
+\cs_new_protected_nopar:Npn \regex_build_one_:
+ {
+ \regex_build_transition_aux:NN
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_?: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_??: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_*: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_build_tmp_class:n \l_regex_left_state_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_*?: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_build_tmp_class:n \l_regex_left_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_+: }
+ {
+ \regex_build_one_:
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_tmpa_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_+?: }
+ {
+ \regex_build_one_:
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_tmpa_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_one_n: #1
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_right_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_tmpa_int
+ { %^^A safe \if nesting?
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \else:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_build_tmp_class:n
+ { \int_use:N \l_regex_tmpa_int }
+ }
+ }
+\cs_new_eq:cN { regex_build_one_n?: } \regex_build_one_n:
+\cs_new_protected_nopar:Npn \regex_build_one_nn: #1#2
+ {
+ \regex_build_one_nn_aux:nn {#1}
+ {
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \regex_action_repeat_copy:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \fi:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_nn?: } #1#2
+ {
+ \regex_build_one_nn_aux:nn {#1}
+ {
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \fi:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_one_nn_aux:nn #1#2
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_right_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_tmpa_int
+ {
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \else:
+ #2
+ \exp_not:N \fi:
+ }
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_build_tmp_class:n
+ { \int_use:N \l_regex_tmpa_int }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_(: } #1#2
+ {
+ \str_if_eq:nnTF { #1 #2 } { \regex_build_control:N ? }
+ { \regex_build_special_group:NN }
+ {
+ \int_incr:N \l_regex_capturing_group_int
+ \seq_push:Nx \l_regex_capturing_group_seq
+ { \int_use:N \l_regex_capturing_group_int }
+ \regex_build_open_aux:
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_open_aux:
+ {
+ \regex_build_new_state:
+ \seq_push:Nx \l_regex_left_state_seq
+ { \int_use:N \l_regex_left_state_int }
+ \seq_push:Nx \l_regex_right_state_seq
+ { \int_use:N \l_regex_right_state_int }
+ \regex_build_begin_alternation:
+ }
+\cs_new_protected_nopar:cpn { regex_build_|: }
+ {
+ \regex_build_end_alternation:
+ \regex_build_begin_alternation:
+ }
+\cs_new_protected_nopar:cpn { regex_build_): }
+ {
+ \seq_if_empty:NTF \l_regex_capturing_group_seq
+ { \regex_build_error:n {22} }
+ {
+ \regex_build_close_aux:
+ \regex_build_group_quantifier:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_close_aux:
+ {
+ \regex_build_end_alternation:
+ \seq_pop:NN \l_regex_left_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_left_state_int \l_regex_tmpa_tl
+ \seq_pop:NN \l_regex_right_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_right_state_int \l_regex_tmpa_tl
+ }
+\cs_new_protected_nopar:Npn \regex_build_begin_alternation:
+ {
+ \regex_build_new_state:
+ \seq_get:NN \l_regex_left_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_left_state_int \l_regex_tmpa_tl
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+\cs_new_protected_nopar:Npn \regex_build_end_alternation:
+ {
+ \seq_get:NN \l_regex_right_state_seq \l_regex_tmpa_tl
+ \regex_toks_put_right:Nx \l_regex_right_state_int
+ { \regex_action_free:n { \l_regex_tmpa_tl } }
+ }
+\cs_new_protected_nopar:Npn \regex_build_special_group:NN #1#2
+ {
+ \cs_if_exist_use:cF { regex_build_special_group_\token_to_str:N #2 : }
+ {
+ \regex_build_error:n { -998 }
+ \regex_build_control:N ( % )
+ \regex_build_raw:N ?
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_special_group_:: }
+ {
+ \seq_push:Nx \l_regex_capturing_group_seq { * }
+ \regex_build_open_aux:
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_quantifier:
+ {
+ \tl_set:Nn \l_regex_one_or_group_tl { group }
+ \regex_build_quantifier:w
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_submatches:NN #1#2
+ {
+ \seq_pop:NN \l_regex_capturing_group_seq \l_regex_tmpa_tl
+ \str_if_eq:xxF { \l_regex_tmpa_tl } { * }
+ {
+ \regex_toks_put_left:Nx #1
+ { \regex_action_submatch:n { \l_regex_tmpa_tl < } }
+ \regex_toks_put_left:Nx #2
+ { \regex_action_submatch:n { \l_regex_tmpa_tl > } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_:
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_shift:N #1
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_new_state:
+ \tex_toks:D \l_regex_right_state_int = \tex_toks:D \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ { \s_regex_toks #1 { \int_use:N \l_regex_right_state_int } }
+ }
+ \regex_build_group_submatches:NN
+ \l_regex_right_state_int \l_regex_left_state_int
+ \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_qs_aux:NN #1#2
+ {
+ \regex_build_group_shift:N \regex_action_free:n
+ \regex_build_transition_aux:NN \regex_action_free:n #1
+ #2 \l_regex_tmpa_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_?: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_right_state_int \regex_toks_put_right:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_??: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_right_state_int \regex_toks_put_left:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_*: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_tmpa_int \regex_toks_put_right:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_*?: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_tmpa_int \regex_toks_put_left:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_+: }
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_tmpa_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_+?: }
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_tmpa_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_n: #1
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ }
+ }
+\cs_new_eq:cN { regex_build_group_n?: } \regex_build_group_n:
+\cs_new_protected_nopar:Npn \regex_build_group_nn: #1#2
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \fi:
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_nn?: } #1#2
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \fi:
+ \exp_not:N \fi:
+ }
+ }
+ }
+\cs_new_protected:Npn \regex_if_state_free:nT #1
+ {
+ \if_num:w \tex_dimen:D #1 = \l_regex_unique_step_int
+ \exp_after:wN \use_none:n
+ \else:
+ \exp_after:wN \use:n
+ \fi:
+ }
+\cs_new_protected:Npn \regex_store_state:n #1
+ {
+ \int_incr:N \l_regex_max_index_int
+ \tex_skip:D \l_regex_max_index_int #1 sp \scan_stop:
+ \regex_store_submatches:n {#1}
+ }
+\cs_new_protected_nopar:Npn \regex_state_use_submatches:
+ { \regex_state_use_aux:n { } }
+\cs_new_protected_nopar:Npn \regex_state_use:
+ { \regex_state_use_aux:n { \exp_after:wN \regex_state_use_aux_ii:w } }
+\cs_new:Npn \regex_state_use_aux_ii:w #1 \s_regex_toks { }
+\cs_new_protected:Npn \regex_state_use_aux:n #1
+ {
+ \regex_if_state_free:nT { \l_regex_current_state_int }
+ {
+ \tex_dimen:D \l_regex_current_state_int
+ = \l_regex_unique_step_int sp \scan_stop:
+ #1 \tex_the:D \tex_toks:D \l_regex_current_state_int \scan_stop:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_disable_submatches:
+ {
+ \cs_set_eq:NN \regex_state_use_submatches: \regex_state_use:
+ \cs_set_eq:NN \regex_store_submatches:n
+ \regex_protected_use_none:n
+ \cs_set_eq:NN \regex_action_submatches:n
+ \regex_protected_use_none:n
+ }
+\cs_new_protected:Npn \regex_protected_use_none:n #1 { }
+\cs_new_protected:Npn \regex_store_submatches:n #1
+ {
+ \exp_after:wN \regex_store_submatches_aux:Nw
+ \exp_after:wN \l_regex_current_submatches_prop
+ \tex_the:D \tex_toks:D #1 \scan_stop: \q_stop
+ { #1 }
+ }
+\cs_new_protected:Npn \regex_store_submatches_aux:Nw #1 #2 \s_regex_toks
+ {
+ \exp_args:No \regex_store_submatches_aux_ii:wnnwwn { #1 }
+ #2
+ \regex_state_submatches:nn { \c_minus_one } { \q_prop }
+ \s_regex_toks
+ }
+\cs_new_protected:Npn \regex_store_submatches_aux_ii:wnnwwn
+ #1 \regex_state_submatches:nn #2#3 #4 \s_regex_toks #5 \q_stop #6
+ {
+ \tex_toks:D #6 \exp_after:wN
+ {
+ \exp_after:wN \regex_state_submatches:nn \exp_after:wN
+ { \int_value:w \int_eval:w \l_regex_unique_step_int + \c_one }
+ { #1 }
+ \regex_state_submatches:nn {#2} {#3}
+ \s_regex_toks
+ #5
+ }
+ }
+\cs_new_protected:Npn \regex_state_submatches:nn #1#2
+ {
+ \if_num:w #1 = \l_regex_unique_step_int
+ \tl_set:Nn \l_regex_current_submatches_prop {#2}
+ \fi:
+ }
+\cs_new_protected:Npn \regex_match:n #1
+ {
+ \tl_set:Nx \l_regex_query_str { \tl_to_other_str:n {#1} }
+ \regex_match_initial_setup:
+ \regex_match_once:
+ }
+\cs_new_protected_nopar:Npn \regex_match_once:
+ {
+ \regex_match_setup:
+ \exp_after:wN \regex_match_once_aux: \l_regex_query_str
+ \q_recursion_tail \q_recursion_stop
+ \bool_if:NT \l_regex_success_bool { \l_regex_every_match_tl }
+ }
+\cs_new_protected_nopar:Npn \regex_match_once_aux:
+ { \str_skip_do:nn { \l_regex_start_step_int } { \regex_match_loop:N } }
+\cs_new_protected_nopar:Npn \regex_match_initial_setup:
+ {
+ \tl_clear:N \l_regex_look_behind_str
+ \prg_stepwise_inline:nnnn {1} {1} { \l_regex_max_state_int }
+ { \tex_dimen:D ##1 \c_minus_one sp \scan_stop: }
+ \int_set_eq:NN \l_regex_unique_step_int \c_minus_one
+ \int_set_eq:NN \l_regex_start_step_int \c_minus_one
+ \int_set_eq:NN \l_regex_current_step_int \c_zero
+ \int_set_eq:NN \l_regex_success_step_int \c_zero
+ \bool_set_false:N \l_regex_success_empty_bool
+ }
+\cs_new_protected_nopar:Npn \regex_match_setup:
+ {
+ \prop_clear:N \l_regex_current_submatches_prop
+ \bool_if:NTF \l_regex_success_empty_bool
+ { \cs_set_eq:NN \regex_last_match_empty:F \regex_last_match_empty_yes:F }
+ { \cs_set_eq:NN \regex_last_match_empty:F \regex_last_match_empty_no:F }
+ \int_set_eq:NN \l_regex_start_step_int \l_regex_success_step_int
+ \int_set_eq:NN \l_regex_current_step_int \l_regex_start_step_int
+ \int_decr:N \l_regex_current_step_int
+ \bool_set_false:N \l_regex_success_bool
+ \int_zero:N \l_regex_max_index_int
+ \regex_store_state:n {1}
+ }
+\cs_new_protected_nopar:Npn \regex_match_loop_setup:
+ {
+ \int_incr:N \l_regex_current_step_int
+ \int_incr:N \l_regex_unique_step_int
+ \bool_set_false:N \l_regex_fresh_thread_bool
+ }
+\cs_new_eq:NN \s_regex_step \scan_stop:
+\cs_new:Npn \regex_break_step:w #1 \s_regex_step { }
+\cs_new_protected_nopar:Npn \regex_match_loop:N #1
+ {
+ \regex_match_loop_setup:
+ \token_if_eq_meaning:NNTF #1 \q_recursion_tail
+ { \int_set_eq:NN \l_regex_current_char_int \c_minus_one }
+ { \int_set:Nn \l_regex_current_char_int {`#1} }
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \int_zero:N \l_regex_max_index_int
+ \prg_stepwise_function:nnnN
+ {1} {1} { \l_regex_max_index_int }
+ \regex_match_one_index:n
+ }
+ \regex_tmp:w
+ \s_regex_step
+ \if_num:w \l_regex_max_index_int = \c_zero
+ \exp_after:wN \use_none_delimit_by_q_recursion_stop:w
+ \fi:
+ \quark_if_recursion_tail_stop:N #1
+ \bool_if:NT \l_regex_look_behind_bool
+ { \tl_put_left:Nx \l_regex_look_behind_str {#1} }
+ \regex_match_loop:N
+ }
+\cs_new_nopar:Npn \regex_match_one_index:n #1
+ {
+ \regex_match_one_index_aux:n { \int_value:w \tex_skip:D #1 }
+ }
+\cs_new_protected_nopar:Npn \regex_match_one_index_aux:n #1
+ {
+ \int_set:Nn \l_regex_current_state_int {#1}
+ \prop_clear:N \l_regex_current_submatches_prop
+ \regex_state_use_submatches:
+ }
+\cs_new_protected_nopar:Npn \regex_action_start_wildcard:nn #1#2
+ {
+ \bool_set_true:N \l_regex_fresh_thread_bool
+ \regex_action_free:n {#2}
+ \bool_set_false:N \l_regex_fresh_thread_bool
+ \regex_action_cost:n {#1}
+ }
+\cs_new_protected_nopar:Npn \regex_action_cost:n #1
+ { \regex_store_state:n {#1} }
+\cs_new_protected_nopar:Npn \regex_action_success:
+ {
+ \regex_last_match_empty:F
+ {
+ \bool_set_true:N \l_regex_success_bool
+ \bool_set_eq:NN \l_regex_success_empty_bool
+ \l_regex_fresh_thread_bool
+ \int_set_eq:NN \l_regex_success_step_int
+ \l_regex_current_step_int
+ \prop_set_eq:NN \l_regex_success_submatches_prop
+ \l_regex_current_submatches_prop
+ \regex_break_step:w
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_action_free:n #1
+ {
+ \regex_if_state_free:nT {#1}
+ {
+ \use:x
+ {
+ \int_set:Nn \l_regex_current_state_int {#1}
+ \regex_store_submatches:n { \l_regex_current_state_int }
+ \regex_state_use:
+ \int_set:Nn \l_regex_current_state_int
+ { \int_use:N \l_regex_current_state_int }
+ \tl_set:Nn \exp_not:N \l_regex_current_submatches_prop
+ { \exp_not:o \l_regex_current_submatches_prop }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_action_submatch:n #1
+ {
+ \prop_put:Nno \l_regex_current_submatches_prop {#1}
+ { \int_use:N \l_regex_current_step_int }
+ \regex_store_submatches:n { \l_regex_current_state_int }
+ }
+\cs_new_protected_nopar:Npn \regex_action_repeat_copy:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_repeat_move:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_no_repeat_copy:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_no_repeat_move:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_extract:
+ {
+ \seq_gclear:N \g_regex_submatches_seq
+ \prg_stepwise_inline:nnnn
+ {0} {1} { \l_regex_capturing_group_int }
+ {
+ \regex_extract_aux:nTF { ##1 }
+ {
+ \seq_gput_right:Nx \g_regex_submatches_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \l_regex_tmpa_tl }
+ { \l_regex_tmpb_tl }
+ }
+ }
+ { \seq_gput_right:Nn \g_regex_submatches_seq { } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_extract_aux:nTF #1#2#3
+ {
+ \prop_get:NnNTF \l_regex_success_submatches_prop
+ { #1 < } \l_regex_tmpa_tl
+ {
+ \prop_get:NnNTF \l_regex_success_submatches_prop
+ { #1 > } \l_regex_tmpb_tl
+ {#2}
+ {#3}
+ }
+ {#3}
+ }
+\cs_new_protected_nopar:Npn \regex_set:Nn
+ { \regex_set_aux:NNn \tl_set_eq:NN }
+\cs_new_protected_nopar:Npn \regex_gset:Nn
+ { \regex_set_aux:NNn \tl_gset_eq:NN }
+\cs_new_protected:Npn \regex_set_aux:NNn #1#2#3
+ {
+ \group_begin:
+ \regex_build:n {#3}
+ \tl_gset:Nx \g_regex_tmpa_tl
+ {
+ \exp_not:N \regex_nfa:Nw \exp_not:N #2
+ \l_regex_max_state_int
+ = \int_use:N \l_regex_max_state_int
+ \l_regex_capturing_group_int
+ = \int_use:N \l_regex_capturing_group_int
+ \bool_if:NTF \l_regex_look_behind_bool
+ { \bool_set_true:N \l_regex_look_behind_bool }
+ { \bool_set_false:N \l_regex_look_behind_bool }
+ \prg_stepwise_function:nnnN
+ {1} {1} {\l_regex_max_state_int}
+ \regex_set_aux:n
+ \regex_nfa_end:
+ }
+ \group_end:
+ #1 #2 \g_regex_tmpa_tl
+ }
+\cs_new_nopar:Npn \regex_set_aux:n #1
+ { \tex_toks:D #1 { \tex_the:D \tex_toks:D #1 } }
+\cs_new:Npn \regex_nfa:Nw #1 #2 \regex_nfa_end:
+ { \msg_expandable_error:n { Automaton~#1 used~incorrectly. } }
+\cs_new_eq:NN \regex_nfa_end: \scan_stop:
+\prg_new_protected_conditional:Npnn \regex_check_nfa:N #1 { TF }
+ { \exp_after:wN \regex_check_nfa_aux:Nw #1 \q_stop }
+\cs_new:Npn \regex_check_nfa_aux:Nw #1 #2 \q_stop
+ {
+ \if_meaning:w \regex_nfa:Nw #1
+ \prg_return_true:
+ \else:
+ \msg_error:nnx { regex } { not-nfa } { \token_to_str:N #1 }
+ \prg_return_false:
+ \fi:
+ }
+\msg_new:nnn { regex } { not-nfa }
+ {
+ I~was~expecting~a~regular~expression~variable.\\
+ Instead,~I~got~#1.
+ }
+\cs_new_protected_nopar:Npn \regex_use:N #1
+ { \exp_after:wN \use_none:nn #1 }
+\cs_new_protected:Npn \regex_user_aux:n #1
+ {
+ \group_begin:
+ \tl_clear:N \l_regex_every_match_tl
+ #1
+ \group_end:
+ }
+\cs_new_protected_nopar:Npn \regex_return_after_group:
+ {
+ \if_bool:N \l_regex_success_bool
+ \group_insert_after:N \prg_return_true:
+ \else:
+ \group_insert_after:N \prg_return_false:
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \regex_extract_after_group:N #1
+ {
+ \if_bool:N \l_regex_success_bool
+ \regex_extract:
+ \group_insert_after:N \seq_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_submatches_seq
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \regex_count_after_group:N #1
+ {
+ \group_insert_after:N \int_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_match_count_int
+ }
+\prg_new_protected_conditional:Npnn \regex_match:nn #1#2 { T , F , TF }
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_return_after_group:
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_match:Nn #1#2 { T , F , TF }
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_return_after_group:
+ }
+ }
+ { \prg_return_false: }
+ }
+\cs_new_protected:Npn \regex_count:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \int_gzero:N \g_regex_match_count_int
+ \tl_set:Nn \l_regex_every_match_tl
+ {
+ \int_gincr:N \g_regex_match_count_int
+ \regex_match_once:
+ }
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_count_after_group:N #3
+ }
+ }
+\cs_new_protected:Npn \regex_count:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \int_gzero:N \g_regex_match_count_int
+ \tl_set:Nn \l_regex_every_match_tl
+ {
+ \int_gincr:N \g_regex_match_count_int
+ \regex_match_once:
+ }
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_count_after_group:N #3
+ }
+ }
+ { }
+ }
+\cs_new_protected:Npn \regex_extract:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_extract:nnN #1#2#3 { T , F , TF }
+ {
+ \regex_user_aux:n
+ {
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ \regex_return_after_group:
+ }
+ }
+\cs_new_protected:Npn \regex_extract:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ }
+ }
+ { }
+ }
+\prg_new_protected_conditional:Npnn \regex_extract:NnN #1#2#3 { T , F , TF }
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ \regex_return_after_group:
+ }
+ }
+ { \prg_return_false: }
+ }
+\cs_new_protected:Npn \regex_split:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \seq_gclear:N \g_regex_split_seq
+ \tl_set:Nn \l_regex_every_match_tl { \regex_split_aux: }
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_split_after_group:N #3
+ }
+ }
+\cs_new_protected:Npn \regex_split:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \seq_gclear:N \g_regex_split_seq
+ \tl_set:Nn \l_regex_every_match_tl { \regex_split_aux: }
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_split_after_group:N #3
+ }
+ }
+ { }
+ }
+\cs_new_protected_nopar:Npn \regex_split_aux:
+ {
+ \int_compare:nNnF \l_regex_start_step_int = \l_regex_success_step_int
+ {
+ \regex_extract:
+ \seq_pop:NN \g_regex_submatches_seq \l_regex_tmpa_tl
+ \regex_extract_aux:nTF {0}
+ {
+ \seq_gput_left:Nx \g_regex_submatches_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \l_regex_tmpa_tl }
+ }
+ }
+ { \msg_error:nn { regex } { internal } }
+ \seq_gconcat:NNN \g_regex_split_seq
+ \g_regex_split_seq \g_regex_submatches_seq
+ }
+ \regex_match_once:
+ }
+\cs_new_protected_nopar:Npn \regex_split_after_group:N #1
+ {
+ \int_compare:nNnTF \l_regex_start_step_int = \l_regex_current_step_int
+ {
+ \bool_if:NF \l_regex_success_empty_bool
+ { \seq_gput_right:Nn \g_regex_split_seq { } }
+ }
+ {
+ \seq_gput_right:Nx \g_regex_split_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \int_use:N \l_regex_current_step_int }
+ }
+ }
+ \group_insert_after:N \seq_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_split_seq
+ }
+\cs_new_protected:Npn \regex_replacement:n #1
+ {
+ \str_aux_escape:NNNn
+ \prg_do_nothing:
+ \regex_replacement_escaped:N
+ \regex_replacement_raw:N
+ {#1}
+ \tl_set_eq:NN \l_regex_replacement_tl \g_str_result_tl
+ \tl_set:Nx \l_regex_replacement_tl
+ { \l_regex_replacement_tl \prg_do_nothing: }
+ }
+\cs_new_nopar:Npn \regex_replacement_raw:N { \exp_not:N \prg_do_nothing: }
+\cs_new_nopar:Npn \regex_replacement_escaped:N #1
+ {
+ \if_num:w 9 < 1 #1 \exp_stop_f:
+ \exp_not:N \regex_replacement_escaped_ii:nN {#1}
+ \else:
+ #1
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_replacement_escaped_ii:nN #1#2
+ {
+ \regex_token_if_other_digit:NTF #2
+ { \regex_replacement_escaped_ii:nN {#1#2} }
+ { \exp_not:N \seq_item:Nn \exp_not:N \g_regex_submatches_seq {#1} #2 }
+ }
+\prg_new_conditional:Npnn \regex_token_if_other_digit:N #1 { TF }
+ {
+ \if_num:w 9 < 1 \exp_not:N #1 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \regex_replace_after_group:N #1
+ {
+ \group_insert_after:N \tl_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_replaced_str
+ }
+\cs_new_protected:Npn \regex_replace_once_aux:Nn #1#2
+ {
+ \group_begin:
+ \regex_replace_after_group:N #1
+ \tl_clear:N \l_regex_every_match_tl
+ #2
+ \exp_args:No \regex_match:n {#1}
+ \regex_extract:
+ \regex_extract_aux:nTF {0}
+ {
+ \tl_gset:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str {0} { \l_regex_tmpa_tl }
+ \l_regex_replacement_tl
+ \str_from_to:Nnn \l_regex_query_str
+ { \l_regex_tmpb_tl } { \c_max_int }
+ }
+ }
+ { \tl_gset_eq:NN \g_regex_replaced_str \l_regex_query_str }
+ \group_end:
+ }
+\cs_new_protected:Npn \regex_replace_once:nnN #1#2#3
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ }
+ }
+\cs_new_protected:Npn \regex_replace_once:NnN #1#2#3
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_replace_once:nnN #1#2#3 {T,F,TF}
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ \regex_return_after_group:
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_replace_once:NnN #1#2#3 {T,F,TF}
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ \regex_return_after_group:
+ }
+ }
+\cs_new_protected:Npn \regex_replace_all_aux:Nn #1#2
+ {
+ \group_begin:
+ \regex_replace_after_group:N #1
+ \tl_set:Nn \l_regex_every_match_tl { \regex_replace_all_aux: }
+ \tl_gclear:N \g_regex_replaced_str
+ #2
+ \exp_args:No \regex_match:n {#1}
+ \tl_gput_right:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \c_max_int }
+ }
+ \group_end:
+ }
+\cs_new_protected_nopar:Npn \regex_replace_all_aux:
+ {
+ \regex_extract:
+ \regex_extract_aux:nTF {0}
+ {
+ \tl_gput_right:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \l_regex_tmpa_tl }
+ \l_regex_replacement_tl
+ }
+ }
+ { \msg_error:nn { regex } { internal } }
+ \regex_match_once:
+ }
+\cs_new_protected:Npn \regex_replace_all:nnN #1#2#3
+ {
+ \regex_replace_all_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ }
+ }
+\cs_new_protected:Npn \regex_replace_all:NnN #1#2#3
+ {
+ \regex_replace_all_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ }
+ }
+%%
+%%
+%% End of file `l3regex-trace.sty'.
diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty
new file mode 100644
index 00000000000..5da00fdd3d0
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3regex.sty
@@ -0,0 +1,1637 @@
+%%
+%% This is file `l3regex.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% l3regex.dtx (with options: `package')
+%%
+%% EXPERIMENTAL CODE
+%%
+%% Do not distribute this file without also distributing the
+%% source files specified above.
+%%
+%% Do not distribute a modified version of this file.
+%%
+%% File: l3regex.dtx Copyright (C) 2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX3 Project.
+%%
+%% -----------------------------------------------------------------------
+\RequirePackage{expl3}
+\GetIdInfo$Id: l3regex.dtx 2895 2011-10-09 15:58:19Z joseph $
+ {L3 Experimental Regular Expressions}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\RequirePackage{l3str}
+\cs_new:Npn \regex_tmp:w { }
+\tl_new:N \g_regex_tmpa_tl
+\tl_new:N \l_regex_tmpa_tl
+\tl_new:N \l_regex_tmpb_tl
+\int_new:N \l_regex_tmpa_int
+\tl_new:N \l_regex_pattern_str
+\int_new:N \l_regex_max_state_int
+\int_new:N \l_regex_left_state_int
+\int_new:N \l_regex_right_state_int
+\seq_new:N \l_regex_left_state_seq
+\seq_new:N \l_regex_right_state_seq
+\int_new:N \l_regex_capturing_group_int
+\seq_new:N \l_regex_capturing_group_seq
+\tl_new:N \l_regex_one_or_group_tl
+\int_new:N \l_regex_repetition_int
+\bool_new:N \l_regex_look_behind_bool
+\tl_new:N \l_regex_look_behind_str
+\cs_new_eq:NN \regex_build_tmp_class:n \use_none:n
+\bool_new:N \l_regex_class_bool
+\tl_new:N \l_regex_class_tl
+\tl_const:Nn \c_regex_d_tl
+ {
+ \regex_item_range:nn {48} {57} % 0--9
+ }
+\tl_const:Nn \c_regex_D_tl
+ {
+ \regex_item_more:n {57} % 9
+ \regex_item_range:nn {0} {47} % 0
+ }
+\tl_const:Nn \c_regex_h_tl
+ {
+ \regex_item_equal:n {32} % space
+ \regex_item_equal:n {9} % tab
+ }
+\tl_const:Nn \c_regex_H_tl
+ {
+ \regex_item_neq:n {32} % space
+ \regex_item_neq:n {9} % tab
+ \regex_break_true:w
+ }
+\tl_const:Nn \c_regex_s_tl
+ {
+ \regex_item_equal:n {32} % space
+ \regex_item_neq:n {11} % vtab
+ \regex_item_range:nn {9} {13} % tab, lf, vtab, ff, cr
+ }
+\tl_const:Nn \c_regex_S_tl
+ {
+ \regex_item_more:n {32} % > space
+ \regex_item_range:nn {14} {31} % tab < ... < space
+ \regex_item_range:nn {0} {8} % < tab
+ \regex_item_equal:n {11} % vtab
+ }
+\tl_const:Nn \c_regex_v_tl
+ {
+ \regex_item_range:nn {10} {13} % lf, vtab, ff, cr
+ }
+\tl_const:Nn \c_regex_V_tl
+ {
+ \regex_item_more:n {13} % cr
+ \regex_item_range:nn {0} {9} % < lf
+ }
+\tl_const:Nn \c_regex_w_tl
+ {
+ \regex_item_range:nn {97} {122} % a--z
+ \regex_item_range:nn {65} {90} % A--Z
+ \regex_item_range:nn {48} {57} % 0--9
+ \regex_item_equal:n {95} % _
+ }
+\tl_const:Nn \c_regex_W_tl
+ {
+ \regex_item_range:nn {0} {47} % <`0
+ \regex_item_range:nn {58} {64} % (`9+1)--(`A-1)
+ \regex_item_range:nn {91} {94} % (`Z+1)--(`_-1)
+ \regex_item_equal:n {96} % `
+ \regex_item_more:n {122} % z
+ }
+\tl_const:Nn \c_regex_N_tl
+ {
+ \regex_item_neq:n {10} % lf
+ \regex_break_true:w
+ }
+\tl_new:N \l_regex_query_str
+\int_new:N \l_regex_start_step_int
+\int_new:N \l_regex_current_char_int
+\int_new:N \l_regex_current_step_int
+\int_new:N \l_regex_unique_step_int
+\int_new:N \l_regex_current_state_int
+\prop_new:N \l_regex_current_submatches_prop
+\int_new:N \l_regex_max_index_int
+\tl_new:N \l_regex_every_match_tl
+\cs_new_protected:Npn \regex_last_match_empty_no:F #1 {#1}
+\cs_new_protected:Npn \regex_last_match_empty_yes:F
+ { \int_compare:nNnF \l_regex_start_step_int = \l_regex_current_step_int }
+\cs_new_eq:NN \regex_last_match_empty:F \regex_last_match_empty_no:F
+\bool_new:N \l_regex_success_bool
+\bool_new:N \l_regex_success_empty_bool
+\int_new:N \l_regex_success_step_int
+\prop_new:N \l_regex_success_submatches_prop
+\bool_new:N \l_regex_fresh_thread_bool
+\seq_new:N \g_regex_submatches_seq
+\int_new:N \g_regex_match_count_int
+\seq_new:N \g_regex_split_seq
+\tl_new:N \l_regex_replacement_tl
+\tl_new:N \g_regex_replaced_str
+\cs_new_eq:NN \s_regex_toks \scan_stop:
+\cs_new_protected:Npn \regex_toks_put_left:Nx #1#2
+ {
+ \cs_set_nopar:Npx \regex_tmp:w \s_regex_toks { \s_regex_toks #2 }
+ \tex_toks:D #1 \exp_after:wN \exp_after:wN \exp_after:wN
+ { \exp_after:wN \regex_tmp:w \tex_the:D \tex_toks:D #1 }
+ }
+\cs_new_protected:Npn \regex_toks_put_right:Nx #1#2
+ {
+ \cs_set_nopar:Npx \regex_tmp:w {#2}
+ \tex_toks:D #1 \exp_after:wN
+ { \tex_the:D \tex_toks:D \exp_after:wN #1 \regex_tmp:w }
+ }
+\cs_new_eq:NN \regex_if_tail_stop:N \quark_if_recursion_tail_stop:N
+\cs_new_protected_nopar:Npn \regex_if_tail_error:Nn #1#2
+ { \quark_if_recursion_tail_stop_do:Nn #1 { \regex_build_error:n {#2} } }
+\cs_new_protected_nopar:Npn \regex_build_error:n #1
+ {
+ \msg_error:nnxx { regex } { build-error } {\int_eval:n{#1}}
+ {
+ \prg_case_int:nnn {#1}
+ {
+ {-999} {File~not~found}
+ {-998} {Unsupported~construct}
+ {-997} {The~regular~expression~is~too~large~(32768~states).}
+ {1} {\iow_char:N\\~at~end~of~pattern }
+ {4} {Numbers~out~of~order~in~\iow_char:N\{\iow_char\}~quantifier.}
+ {6} {Missing~terminating~\iow_char:N\]~for~character~class }
+ {7} {Invalid~escape~sequence~in~character~class}
+ {8} {Range~out~of~order~in~character~class}
+ {22} {Mismatched~parentheses}
+ {34} {Character~value~in~\iow_char:N\\x{...}~sequence~is~too~large}
+ }
+ { Internal~bug. }
+ }
+ }
+\msg_new:nnn { regex } { build-error } { (error~#1): ~ #2 }
+\cs_new_nopar:Npn \regex_break_true:w #1 \regex_break_point:TF #2 #3 {#2}
+\cs_new_nopar:Npn \regex_break_false:w #1 \regex_break_point:TF #2 #3 {#3}
+\cs_new_eq:NN \regex_break_point:TF \use_ii:nn
+\cs_new_nopar:Npn \regex_item_equal:n #1
+ {
+ \if_num:w #1 = \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_range:nn #1 #2
+ {
+ \reverse_if:N \if_num:w #1 > \l_regex_current_char_int
+ \reverse_if:N \if_num:w #2 < \l_regex_current_char_int
+ \exp_after:wN \exp_after:wN \exp_after:wN \regex_break_true:w
+ \fi:
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_less:n #1
+ {
+ \if_num:w #1 > \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_more:n #1
+ {
+ \if_num:w #1 < \l_regex_current_char_int
+ \exp_after:wN \regex_break_true:w
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_item_neq:n #1
+ {
+ \if_num:w #1 = \l_regex_current_char_int
+ \exp_after:wN \regex_break_false:w
+ \fi:
+ }
+\cs_new_protected:Npn \regex_get_digits:nw #1
+ {
+ \tex_afterassignment:D \regex_tmp:w
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \exp_not:n {#1}
+ { \if_false: } } \fi:
+ \regex_get_digits_aux:N
+ }
+\cs_new_nopar:Npn \regex_get_digits_aux:N #1
+ {
+ \if_num:w 9 < 1 \exp_not:N #1 \exp_stop_f:
+ \else:
+ \if_charcode:w \c_space_token \exp_not:N #1
+ \else:
+ \regex_get_digits_end:w
+ \fi:
+ \fi:
+ #1 \regex_get_digits_aux:N
+ }
+\cs_new_nopar:Npn \regex_get_digits_end:w
+ \fi: \fi: #1 \regex_get_digits_aux:N
+ {
+ \fi: \fi:
+ \if_false: { { \fi: } }
+ #1
+ }
+\prg_new_conditional:Npnn \regex_aux_char_if_special:N #1 { TF }
+ {
+ \if_num:w `#1 < 97 \exp_stop_f:
+ \if_num:w `#1 < 58 \exp_stop_f:
+ \if_num:w \int_eval:w (`#1 - \c_eight)/\c_sixteen = \c_two
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w `#1 / 26 = \c_three
+ \prg_return_false:
+ \else:
+ \prg_return_true:
+ \fi:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w `#1 / \c_five = 25 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \fi:
+ }
+\prg_new_conditional:Npnn \regex_aux_char_if_alphanumeric:N #1 { TF }
+ {
+ \if_num:w `#1 < 91 \exp_stop_f:
+ \if_num:w `#1 < 65 \exp_stop_f:
+ \if_num:w \c_nine < 1 #1 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \else:
+ \prg_return_true:
+ \fi:
+ \else:
+ \if_num:w \int_eval:w (`#1-\c_six)/26 = \c_four
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \regex_build_new_state:
+ {
+ \int_compare:nNnTF \l_regex_max_state_int > {32766}
+ { \regex_build_error:n {-997} }
+ {
+ \int_incr:N \l_regex_max_state_int
+ \tex_toks:D \l_regex_max_state_int { \s_regex_toks }
+ }
+ \int_set_eq:NN \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_right_state_int \l_regex_max_state_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_transition_aux:NN #1#2
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ { #1 { \int_use:N #2 } }
+ }
+\cs_new_protected_nopar:Npn \regex_build_transitions_aux:NNNN #1#2#3#4
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ #1 { \int_use:N #2 }
+ #3 { \int_use:N #4 }
+ }
+ }
+\cs_new_protected:Npn \regex_build:n #1
+ {
+ \regex_build_setup:
+ \str_aux_escape:NNNn
+ \regex_build_i_unescaped:N
+ \regex_build_i_escaped:N
+ \regex_build_i_raw:N
+ { #1 }
+ \regex_build_open_aux:
+ \g_str_result_tl \prg_do_nothing: \prg_do_nothing:
+ \seq_push:Nn \l_regex_capturing_group_seq { 0 }
+ \regex_build_close_aux: \regex_build_group_:
+ \regex_build_end:
+ }
+\cs_new_nopar:Npn \regex_build_i_unescaped:N #1
+ {
+ \regex_aux_char_if_special:NTF #1
+ { \exp_not:N \regex_build_control:N #1 }
+ { \exp_not:N \regex_build_raw:N #1 }
+ }
+\cs_new_nopar:Npn \regex_build_i_escaped:N #1
+ {
+ \regex_aux_char_if_alphanumeric:NTF #1
+ { \exp_not:N \regex_build_control:N #1 }
+ { \exp_not:N \regex_build_raw:N #1 }
+ }
+\cs_new_nopar:Npn \regex_build_i_raw:N #1
+ { \exp_not:N \regex_build_raw:N #1 }
+\cs_new_protected_nopar:Npn \regex_build_default_control:N #1
+ {
+ \cs_if_exist_use:cF { regex_build_#1: }
+ { \regex_build_default_raw:N #1 }
+ }
+\cs_new_protected_nopar:Npn \regex_build_setup:
+ {
+ \cs_set_eq:NN \regex_build_control:N \regex_build_default_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_build_default_raw:N
+ \int_set_eq:NN \l_regex_capturing_group_int \c_zero
+ \int_zero:N \l_regex_left_state_int
+ \int_zero:N \l_regex_right_state_int
+ \int_zero:N \l_regex_max_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_action_start_wildcard:nn
+ { \int_use:N \l_regex_left_state_int }
+ { \int_use:N \l_regex_right_state_int }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_end:
+ {
+ \seq_if_empty:NF \l_regex_capturing_group_seq
+ {
+ \regex_build_error:n {22}
+ \prg_replicate:nn
+ { \seq_length:N \l_regex_capturing_group_seq } % (
+ { \regex_build_close_aux: \regex_build_group_: }
+ }
+ \regex_toks_put_right:Nx \l_regex_right_state_int
+ { \regex_action_success: }
+ }
+\cs_new_protected_nopar:cpn { regex_build_^: }
+ { \regex_build_anchor_start:N \c_zero }
+\cs_new_protected_nopar:Npn \regex_build_A:
+ { \regex_build_anchor_start:N \c_zero }
+\cs_new_protected_nopar:Npn \regex_build_G:
+ { \regex_build_anchor_start:N \l_regex_start_step_int }
+\cs_new_protected_nopar:Npn \regex_build_anchor_start:N #1
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \int_compare:nNnT {#1} = \l_regex_current_step_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_$: } % $
+ {
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \int_compare:nNnT
+ \c_minus_one = \l_regex_current_char_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+\cs_new_eq:Nc \regex_build_Z: { regex_build_$: } %$
+\cs_new_eq:Nc \regex_build_z: { regex_build_$: } %$
+\cs_new_protected_nopar:Npn \regex_build_b:
+ {
+ \bool_set_true:N \l_regex_look_behind_bool
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \regex_if_word_boundary:TF
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ { }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_B:
+ {
+ \bool_set_true:N \l_regex_look_behind_bool
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \exp_not:N \regex_if_word_boundary:TF
+ { }
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_if_word_boundary:TF
+ {
+ \tl_if_empty:NTF \l_regex_look_behind_str
+ { \c_regex_w_tl }
+ {
+ \group_begin:
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \int_set:Nn \l_regex_current_char_int
+ { ` \str_head:N \l_regex_look_behind_str }
+ }
+ \regex_tmp:w
+ \c_regex_w_tl
+ \regex_break_point:TF
+ { \group_end: \c_regex_W_tl }
+ { \group_end: \c_regex_w_tl }
+ }
+ \regex_break_point:TF
+ }
+\cs_new_protected_nopar:Npn \regex_build_default_raw:N #1
+ {
+ \cs_set:Npx \regex_build_tmp_class:n ##1
+ {
+ \exp_not:n { \exp_not:N \if_num:w }
+ \int_value:w `#1 = \l_regex_current_char_int
+ \regex_action_cost:n { ##1 }
+ \exp_not:n { \exp_not:N \fi: }
+ }
+ \regex_build_one_quantifier:
+ }
+\cs_new_protected_nopar:cpn { regex_build_.: }
+ {
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:N \if_num:w \c_minus_one < \l_regex_current_char_int
+ \regex_action_cost:n {##1}
+ \exp_not:N \fi:
+ }
+ \regex_build_one_quantifier:
+ }
+\cs_new_protected_nopar:Npn \regex_build_char_type:N #1
+ {
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:N #1
+ \exp_not:N \regex_break_point:TF
+ { \regex_action_cost:n {##1} }
+ { }
+ }
+ \regex_build_one_quantifier:
+ }
+\tl_map_inline:nn { dDhHsSvVwWN }
+ {
+ \cs_new_protected_nopar:cpx { regex_build_#1: }
+ {
+ \exp_not:N \regex_build_char_type:N
+ \exp_not:c { c_regex_#1_tl }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_[: }
+ {
+ \tl_clear:N \l_regex_class_tl
+ \cs_set_eq:NN \regex_build_control:N \regex_class_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_class_raw:N
+ \regex_class_first:NN
+ }
+\cs_new_protected_nopar:Npn \regex_class_control:N #1
+ {
+ \cs_if_exist_use:cF { regex_class_#1: }
+ { \regex_class_raw:N #1 }
+ }
+\cs_new_protected_nopar:cpn { regex_class_]: }
+ {
+ \tl_if_empty:NTF \l_regex_class_tl %[
+ { \regex_class_raw:N ] }
+ {
+ \cs_set_eq:NN \regex_build_control:N \regex_build_default_control:N
+ \cs_set_eq:NN \regex_build_raw:N \regex_build_default_raw:N
+ \cs_set:Npn \regex_build_tmp_class:n ##1
+ {
+ \exp_not:o \l_regex_class_tl
+ \bool_if:NTF \l_regex_class_bool
+ {
+ \exp_not:N \regex_break_point:TF
+ { \regex_action_cost:n {##1} }
+ { }
+ }
+ {
+ \exp_not:N \regex_break_point:TF
+ { }
+ { \regex_action_cost:n {##1} }
+ }
+ }
+ \regex_build_one_quantifier:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_class_first:NN #1#2
+ {
+ \str_if_eq:nnTF {#1#2} { \regex_build_control:N ^ }
+ { \bool_set_false:N \l_regex_class_bool }
+ {
+ \bool_set_true:N \l_regex_class_bool
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_class_raw:N #1#2#3
+ {
+ \str_if_eq:nnTF {#2#3} { \regex_build_control:N - }
+ { \regex_class_range:Nw #1 }
+ {
+ \regex_class_single:N #1
+ #2 #3
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_class_single:N #1
+ {
+ \tl_put_right:Nx \l_regex_class_tl
+ { \exp_not:N \regex_item_equal:n { \int_value:w `#1 } }
+ }
+\cs_new_protected_nopar:Npn \regex_class_range:Nw #1#2#3
+ {
+ \token_if_eq_meaning:NNTF #2 \regex_build_control:N
+ {
+ \cs_if_exist:cTF { regex_class_#3: }
+ {
+ \regex_class_single:N #1
+ \regex_class_single:N -
+ #2#3
+ }
+ { \regex_class_range_put:NN #1#3 }
+ }
+ { \regex_class_range_put:NN #1#3 }
+ }
+\cs_new_protected_nopar:Npn \regex_class_range_put:NN #1#2
+ {
+ \if_num:w `#1 > `#2 \exp_stop_f:
+ \regex_build_error:n {8}
+ \else:
+ \tl_put_right:Nx \l_regex_class_tl
+ {
+ \if_num:w `#1 = `#2 \exp_stop_f:
+ \exp_not:N \regex_item_equal:n
+ \else:
+ \exp_not:N \regex_item_range:nn { \int_value:w `#1 }
+ \fi:
+ { \int_value:w `#2 }
+ }
+ \fi:
+ }
+\tl_map_inline:nn { dDhHsSvVwWN }
+ {
+ \cs_new_protected_nopar:cpx { regex_class_#1: }
+ {
+ \tl_put_right:Nn \exp_not:N \l_regex_class_tl
+ { \exp_not:c { c_regex_#1_tl } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_quantifier:w #1#2
+ {
+ \token_if_eq_meaning:NNTF #1 \regex_build_control:N
+ {
+ \cs_if_exist_use:cF { regex_build_quantifier_#2:w }
+ {
+ \regex_build_quantifier_end:n { }
+ #1 #2
+ }
+ }
+ {
+ \regex_build_quantifier_end:n { }
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_?:w }
+ { \regex_build_quantifier_aux:nnNN { } { ? } }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_*:w }
+ { \regex_build_quantifier_aux:nnNN { } { * } }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_+:w }
+ { \regex_build_quantifier_aux:nnNN { } { + } }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_aux:nnNN #1#2#3#4
+ {
+ \str_if_eq:nnTF { #3 #4 } { \regex_build_control:N ? }
+ { \regex_build_quantifier_end:n { #2 #4 } #1 }
+ {
+ \regex_build_quantifier_end:n { #2 } #1
+ #3 #4
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_quantifier_ \c_lbrace_str :w }
+ { \regex_get_digits:nw { \regex_build_quantifier_lbrace:n } }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_lbrace:n #1
+ {
+ \tl_if_empty:nTF {#1}
+ {
+ \regex_build_quantifier_end:n { }
+ \exp_after:wN \regex_build_raw:N \c_lbrace_str
+ }
+ { \regex_build_quantifier_lbrace:nw {#1} }
+ }
+\cs_new_protected_nopar:Npx \regex_build_quantifier_lbrace:nw #1#2#3
+ {
+ \exp_not:N \prg_case_str:nnn { #2 #3 }
+ {
+ { \exp_not:N \regex_build_control:N , }
+ {
+ \exp_not:N \regex_get_digits:nw
+ { \exp_not:N \regex_build_quantifier_lbrace:nnw {#1} }
+ }
+ { \exp_not:N \regex_build_control:N \c_rbrace_str }
+ { \exp_not:N \regex_build_quantifier_end:n {n} {#1} }
+ }
+ {
+ \exp_not:N \regex_build_quantifier_end:n { }
+ \exp_not:N \regex_build_raw:N \c_lbrace_str #1#2
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_lbrace:nnw #1#2#3
+ {
+ \str_if_eq:xxTF { \exp_not:N #3 } { \c_rbrace_str }
+ {
+ \tl_if_empty:nTF {#2}
+ { \regex_build_quantifier_aux:nnN { {#1} {\c_max_int} } {nn} }
+ {
+ \int_compare:nNnT {#1} > {#2}
+ { \regex_build_error:n {4} }
+ \regex_build_quantifier_aux:nnN { {#1} {#2} } {nn}
+ }
+ }
+ {
+ \regex_build_quantifier_end:n { }
+ \use:x
+ {
+ \exp_not:n { \exp_args:No \tl_map_function:nN }
+ { \c_lbrace_str #1 #2 , }
+ \regex_build_raw:N
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_quantifier_end:n #1
+ { \use:c { regex_build_ \l_regex_one_or_group_tl _ #1 : } }
+\cs_new_protected_nopar:Npn \regex_build_one_quantifier:
+ {
+ \tl_set:Nx \l_regex_one_or_group_tl { one }
+ \regex_build_quantifier:w
+ }
+\cs_new_protected_nopar:Npn \regex_build_one_:
+ {
+ \regex_build_transition_aux:NN
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_?: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_??: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_build_tmp_class:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_*: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_build_tmp_class:n \l_regex_left_state_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_*?: }
+ {
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_build_tmp_class:n \l_regex_left_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_+: }
+ {
+ \regex_build_one_:
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_tmpa_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_+?: }
+ {
+ \regex_build_one_:
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_tmpa_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_one_n: #1
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_right_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_tmpa_int
+ { %^^A safe \if nesting?
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \else:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_build_tmp_class:n
+ { \int_use:N \l_regex_tmpa_int }
+ }
+ }
+\cs_new_eq:cN { regex_build_one_n?: } \regex_build_one_n:
+\cs_new_protected_nopar:Npn \regex_build_one_nn: #1#2
+ {
+ \regex_build_one_nn_aux:nn {#1}
+ {
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \regex_action_repeat_copy:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \fi:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_one_nn?: } #1#2
+ {
+ \regex_build_one_nn_aux:nn {#1}
+ {
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \fi:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_one_nn_aux:nn #1#2
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_right_state_int
+ \regex_build_new_state:
+ \regex_build_new_state:
+ \regex_toks_put_right:Nx \l_regex_tmpa_int
+ {
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \regex_action_repeat_move:n
+ { \int_use:N \l_regex_left_state_int }
+ \exp_not:N \else:
+ #2
+ \exp_not:N \fi:
+ }
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ {
+ \regex_build_tmp_class:n
+ { \int_use:N \l_regex_tmpa_int }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_(: } #1#2
+ {
+ \str_if_eq:nnTF { #1 #2 } { \regex_build_control:N ? }
+ { \regex_build_special_group:NN }
+ {
+ \int_incr:N \l_regex_capturing_group_int
+ \seq_push:Nx \l_regex_capturing_group_seq
+ { \int_use:N \l_regex_capturing_group_int }
+ \regex_build_open_aux:
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_open_aux:
+ {
+ \regex_build_new_state:
+ \seq_push:Nx \l_regex_left_state_seq
+ { \int_use:N \l_regex_left_state_int }
+ \seq_push:Nx \l_regex_right_state_seq
+ { \int_use:N \l_regex_right_state_int }
+ \regex_build_begin_alternation:
+ }
+\cs_new_protected_nopar:cpn { regex_build_|: }
+ {
+ \regex_build_end_alternation:
+ \regex_build_begin_alternation:
+ }
+\cs_new_protected_nopar:cpn { regex_build_): }
+ {
+ \seq_if_empty:NTF \l_regex_capturing_group_seq
+ { \regex_build_error:n {22} }
+ {
+ \regex_build_close_aux:
+ \regex_build_group_quantifier:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_close_aux:
+ {
+ \regex_build_end_alternation:
+ \seq_pop:NN \l_regex_left_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_left_state_int \l_regex_tmpa_tl
+ \seq_pop:NN \l_regex_right_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_right_state_int \l_regex_tmpa_tl
+ }
+\cs_new_protected_nopar:Npn \regex_build_begin_alternation:
+ {
+ \regex_build_new_state:
+ \seq_get:NN \l_regex_left_state_seq \l_regex_tmpa_tl
+ \int_set:Nn \l_regex_left_state_int \l_regex_tmpa_tl
+ \regex_toks_put_right:Nx \l_regex_left_state_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+\cs_new_protected_nopar:Npn \regex_build_end_alternation:
+ {
+ \seq_get:NN \l_regex_right_state_seq \l_regex_tmpa_tl
+ \regex_toks_put_right:Nx \l_regex_right_state_int
+ { \regex_action_free:n { \l_regex_tmpa_tl } }
+ }
+\cs_new_protected_nopar:Npn \regex_build_special_group:NN #1#2
+ {
+ \cs_if_exist_use:cF { regex_build_special_group_\token_to_str:N #2 : }
+ {
+ \regex_build_error:n { -998 }
+ \regex_build_control:N ( % )
+ \regex_build_raw:N ?
+ #1 #2
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_special_group_:: }
+ {
+ \seq_push:Nx \l_regex_capturing_group_seq { * }
+ \regex_build_open_aux:
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_quantifier:
+ {
+ \tl_set:Nn \l_regex_one_or_group_tl { group }
+ \regex_build_quantifier:w
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_submatches:NN #1#2
+ {
+ \seq_pop:NN \l_regex_capturing_group_seq \l_regex_tmpa_tl
+ \str_if_eq:xxF { \l_regex_tmpa_tl } { * }
+ {
+ \regex_toks_put_left:Nx #1
+ { \regex_action_submatch:n { \l_regex_tmpa_tl < } }
+ \regex_toks_put_left:Nx #2
+ { \regex_action_submatch:n { \l_regex_tmpa_tl > } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_:
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_shift:N #1
+ {
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_new_state:
+ \tex_toks:D \l_regex_right_state_int = \tex_toks:D \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ { \s_regex_toks #1 { \int_use:N \l_regex_right_state_int } }
+ }
+ \regex_build_group_submatches:NN
+ \l_regex_right_state_int \l_regex_left_state_int
+ \int_set_eq:NN \l_regex_right_state_int \l_regex_left_state_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_qs_aux:NN #1#2
+ {
+ \regex_build_group_shift:N \regex_action_free:n
+ \regex_build_transition_aux:NN \regex_action_free:n #1
+ #2 \l_regex_tmpa_int
+ { \regex_action_free:n { \int_use:N \l_regex_right_state_int } }
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_?: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_right_state_int \regex_toks_put_right:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_??: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_right_state_int \regex_toks_put_left:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_*: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_tmpa_int \regex_toks_put_right:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_*?: }
+ {
+ \regex_build_group_qs_aux:NN
+ \l_regex_tmpa_int \regex_toks_put_left:Nx
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_+: }
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_tmpa_int
+ \regex_action_free:n \l_regex_right_state_int
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_+?: }
+ {
+ \regex_build_group_submatches:NN
+ \l_regex_left_state_int \l_regex_right_state_int
+ \int_set_eq:NN \l_regex_tmpa_int \l_regex_left_state_int
+ \regex_build_transitions_aux:NNNN
+ \regex_action_free:n \l_regex_right_state_int
+ \regex_action_free:n \l_regex_tmpa_int
+ }
+\cs_new_protected_nopar:Npn \regex_build_group_n: #1
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \regex_action_no_repeat_move:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ }
+ }
+\cs_new_eq:cN { regex_build_group_n?: } \regex_build_group_n:
+\cs_new_protected_nopar:Npn \regex_build_group_nn: #1#2
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \fi:
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \fi:
+ }
+ }
+ }
+\cs_new_protected_nopar:cpn { regex_build_group_nn?: } #1#2
+ {
+ \regex_build_group_shift:N \regex_action_repeat_move:n
+ \regex_build_transition_aux:NN
+ \regex_action_free:n \l_regex_tmpa_int
+ \use:x
+ {
+ \tex_toks:D \l_regex_tmpa_int
+ {
+ \s_regex_toks
+ \exp_not:N \if_num:w #1 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \else:
+ \regex_action_no_repeat_copy:n
+ { \int_use:N \l_regex_right_state_int }
+ \exp_not:N \if_num:w #2 > \l_regex_repetition_int
+ \tex_the:D \tex_toks:D \l_regex_tmpa_int
+ \exp_not:N \fi:
+ \exp_not:N \fi:
+ }
+ }
+ }
+\cs_new_protected:Npn \regex_if_state_free:nT #1
+ {
+ \if_num:w \tex_dimen:D #1 = \l_regex_unique_step_int
+ \exp_after:wN \use_none:n
+ \else:
+ \exp_after:wN \use:n
+ \fi:
+ }
+\cs_new_protected:Npn \regex_store_state:n #1
+ {
+ \int_incr:N \l_regex_max_index_int
+ \tex_skip:D \l_regex_max_index_int #1 sp \scan_stop:
+ \regex_store_submatches:n {#1}
+ }
+\cs_new_protected_nopar:Npn \regex_state_use_submatches:
+ { \regex_state_use_aux:n { } }
+\cs_new_protected_nopar:Npn \regex_state_use:
+ { \regex_state_use_aux:n { \exp_after:wN \regex_state_use_aux_ii:w } }
+\cs_new:Npn \regex_state_use_aux_ii:w #1 \s_regex_toks { }
+\cs_new_protected:Npn \regex_state_use_aux:n #1
+ {
+ \regex_if_state_free:nT { \l_regex_current_state_int }
+ {
+ \tex_dimen:D \l_regex_current_state_int
+ = \l_regex_unique_step_int sp \scan_stop:
+ #1 \tex_the:D \tex_toks:D \l_regex_current_state_int \scan_stop:
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_disable_submatches:
+ {
+ \cs_set_eq:NN \regex_state_use_submatches: \regex_state_use:
+ \cs_set_eq:NN \regex_store_submatches:n
+ \regex_protected_use_none:n
+ \cs_set_eq:NN \regex_action_submatches:n
+ \regex_protected_use_none:n
+ }
+\cs_new_protected:Npn \regex_protected_use_none:n #1 { }
+\cs_new_protected:Npn \regex_store_submatches:n #1
+ {
+ \exp_after:wN \regex_store_submatches_aux:Nw
+ \exp_after:wN \l_regex_current_submatches_prop
+ \tex_the:D \tex_toks:D #1 \scan_stop: \q_stop
+ { #1 }
+ }
+\cs_new_protected:Npn \regex_store_submatches_aux:Nw #1 #2 \s_regex_toks
+ {
+ \exp_args:No \regex_store_submatches_aux_ii:wnnwwn { #1 }
+ #2
+ \regex_state_submatches:nn { \c_minus_one } { \q_prop }
+ \s_regex_toks
+ }
+\cs_new_protected:Npn \regex_store_submatches_aux_ii:wnnwwn
+ #1 \regex_state_submatches:nn #2#3 #4 \s_regex_toks #5 \q_stop #6
+ {
+ \tex_toks:D #6 \exp_after:wN
+ {
+ \exp_after:wN \regex_state_submatches:nn \exp_after:wN
+ { \int_value:w \int_eval:w \l_regex_unique_step_int + \c_one }
+ { #1 }
+ \regex_state_submatches:nn {#2} {#3}
+ \s_regex_toks
+ #5
+ }
+ }
+\cs_new_protected:Npn \regex_state_submatches:nn #1#2
+ {
+ \if_num:w #1 = \l_regex_unique_step_int
+ \tl_set:Nn \l_regex_current_submatches_prop {#2}
+ \fi:
+ }
+\cs_new_protected:Npn \regex_match:n #1
+ {
+ \tl_set:Nx \l_regex_query_str { \tl_to_other_str:n {#1} }
+ \regex_match_initial_setup:
+ \regex_match_once:
+ }
+\cs_new_protected_nopar:Npn \regex_match_once:
+ {
+ \regex_match_setup:
+ \exp_after:wN \regex_match_once_aux: \l_regex_query_str
+ \q_recursion_tail \q_recursion_stop
+ \bool_if:NT \l_regex_success_bool { \l_regex_every_match_tl }
+ }
+\cs_new_protected_nopar:Npn \regex_match_once_aux:
+ { \str_skip_do:nn { \l_regex_start_step_int } { \regex_match_loop:N } }
+\cs_new_protected_nopar:Npn \regex_match_initial_setup:
+ {
+ \tl_clear:N \l_regex_look_behind_str
+ \prg_stepwise_inline:nnnn {1} {1} { \l_regex_max_state_int }
+ { \tex_dimen:D ##1 \c_minus_one sp \scan_stop: }
+ \int_set_eq:NN \l_regex_unique_step_int \c_minus_one
+ \int_set_eq:NN \l_regex_start_step_int \c_minus_one
+ \int_set_eq:NN \l_regex_current_step_int \c_zero
+ \int_set_eq:NN \l_regex_success_step_int \c_zero
+ \bool_set_false:N \l_regex_success_empty_bool
+ }
+\cs_new_protected_nopar:Npn \regex_match_setup:
+ {
+ \prop_clear:N \l_regex_current_submatches_prop
+ \bool_if:NTF \l_regex_success_empty_bool
+ { \cs_set_eq:NN \regex_last_match_empty:F \regex_last_match_empty_yes:F }
+ { \cs_set_eq:NN \regex_last_match_empty:F \regex_last_match_empty_no:F }
+ \int_set_eq:NN \l_regex_start_step_int \l_regex_success_step_int
+ \int_set_eq:NN \l_regex_current_step_int \l_regex_start_step_int
+ \int_decr:N \l_regex_current_step_int
+ \bool_set_false:N \l_regex_success_bool
+ \int_zero:N \l_regex_max_index_int
+ \regex_store_state:n {1}
+ }
+\cs_new_protected_nopar:Npn \regex_match_loop_setup:
+ {
+ \int_incr:N \l_regex_current_step_int
+ \int_incr:N \l_regex_unique_step_int
+ \bool_set_false:N \l_regex_fresh_thread_bool
+ }
+\cs_new_eq:NN \s_regex_step \scan_stop:
+\cs_new:Npn \regex_break_step:w #1 \s_regex_step { }
+\cs_new_protected_nopar:Npn \regex_match_loop:N #1
+ {
+ \regex_match_loop_setup:
+ \token_if_eq_meaning:NNTF #1 \q_recursion_tail
+ { \int_set_eq:NN \l_regex_current_char_int \c_minus_one }
+ { \int_set:Nn \l_regex_current_char_int {`#1} }
+ \cs_set_nopar:Npx \regex_tmp:w
+ {
+ \int_zero:N \l_regex_max_index_int
+ \prg_stepwise_function:nnnN
+ {1} {1} { \l_regex_max_index_int }
+ \regex_match_one_index:n
+ }
+ \regex_tmp:w
+ \s_regex_step
+ \if_num:w \l_regex_max_index_int = \c_zero
+ \exp_after:wN \use_none_delimit_by_q_recursion_stop:w
+ \fi:
+ \quark_if_recursion_tail_stop:N #1
+ \bool_if:NT \l_regex_look_behind_bool
+ { \tl_put_left:Nx \l_regex_look_behind_str {#1} }
+ \regex_match_loop:N
+ }
+\cs_new_nopar:Npn \regex_match_one_index:n #1
+ {
+ \regex_match_one_index_aux:n { \int_value:w \tex_skip:D #1 }
+ }
+\cs_new_protected_nopar:Npn \regex_match_one_index_aux:n #1
+ {
+ \int_set:Nn \l_regex_current_state_int {#1}
+ \prop_clear:N \l_regex_current_submatches_prop
+ \regex_state_use_submatches:
+ }
+\cs_new_protected_nopar:Npn \regex_action_start_wildcard:nn #1#2
+ {
+ \bool_set_true:N \l_regex_fresh_thread_bool
+ \regex_action_free:n {#2}
+ \bool_set_false:N \l_regex_fresh_thread_bool
+ \regex_action_cost:n {#1}
+ }
+\cs_new_protected_nopar:Npn \regex_action_cost:n #1
+ { \regex_store_state:n {#1} }
+\cs_new_protected_nopar:Npn \regex_action_success:
+ {
+ \regex_last_match_empty:F
+ {
+ \bool_set_true:N \l_regex_success_bool
+ \bool_set_eq:NN \l_regex_success_empty_bool
+ \l_regex_fresh_thread_bool
+ \int_set_eq:NN \l_regex_success_step_int
+ \l_regex_current_step_int
+ \prop_set_eq:NN \l_regex_success_submatches_prop
+ \l_regex_current_submatches_prop
+ \regex_break_step:w
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_action_free:n #1
+ {
+ \regex_if_state_free:nT {#1}
+ {
+ \use:x
+ {
+ \int_set:Nn \l_regex_current_state_int {#1}
+ \regex_store_submatches:n { \l_regex_current_state_int }
+ \regex_state_use:
+ \int_set:Nn \l_regex_current_state_int
+ { \int_use:N \l_regex_current_state_int }
+ \tl_set:Nn \exp_not:N \l_regex_current_submatches_prop
+ { \exp_not:o \l_regex_current_submatches_prop }
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_action_submatch:n #1
+ {
+ \prop_put:Nno \l_regex_current_submatches_prop {#1}
+ { \int_use:N \l_regex_current_step_int }
+ \regex_store_submatches:n { \l_regex_current_state_int }
+ }
+\cs_new_protected_nopar:Npn \regex_action_repeat_copy:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_repeat_move:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_no_repeat_copy:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_action_no_repeat_move:n { \ERROR }
+\cs_new_protected_nopar:Npn \regex_extract:
+ {
+ \seq_gclear:N \g_regex_submatches_seq
+ \prg_stepwise_inline:nnnn
+ {0} {1} { \l_regex_capturing_group_int }
+ {
+ \regex_extract_aux:nTF { ##1 }
+ {
+ \seq_gput_right:Nx \g_regex_submatches_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \l_regex_tmpa_tl }
+ { \l_regex_tmpb_tl }
+ }
+ }
+ { \seq_gput_right:Nn \g_regex_submatches_seq { } }
+ }
+ }
+\cs_new_protected_nopar:Npn \regex_extract_aux:nTF #1#2#3
+ {
+ \prop_get:NnNTF \l_regex_success_submatches_prop
+ { #1 < } \l_regex_tmpa_tl
+ {
+ \prop_get:NnNTF \l_regex_success_submatches_prop
+ { #1 > } \l_regex_tmpb_tl
+ {#2}
+ {#3}
+ }
+ {#3}
+ }
+\cs_new_protected_nopar:Npn \regex_set:Nn
+ { \regex_set_aux:NNn \tl_set_eq:NN }
+\cs_new_protected_nopar:Npn \regex_gset:Nn
+ { \regex_set_aux:NNn \tl_gset_eq:NN }
+\cs_new_protected:Npn \regex_set_aux:NNn #1#2#3
+ {
+ \group_begin:
+ \regex_build:n {#3}
+ \tl_gset:Nx \g_regex_tmpa_tl
+ {
+ \exp_not:N \regex_nfa:Nw \exp_not:N #2
+ \l_regex_max_state_int
+ = \int_use:N \l_regex_max_state_int
+ \l_regex_capturing_group_int
+ = \int_use:N \l_regex_capturing_group_int
+ \bool_if:NTF \l_regex_look_behind_bool
+ { \bool_set_true:N \l_regex_look_behind_bool }
+ { \bool_set_false:N \l_regex_look_behind_bool }
+ \prg_stepwise_function:nnnN
+ {1} {1} {\l_regex_max_state_int}
+ \regex_set_aux:n
+ \regex_nfa_end:
+ }
+ \group_end:
+ #1 #2 \g_regex_tmpa_tl
+ }
+\cs_new_nopar:Npn \regex_set_aux:n #1
+ { \tex_toks:D #1 { \tex_the:D \tex_toks:D #1 } }
+\cs_new:Npn \regex_nfa:Nw #1 #2 \regex_nfa_end:
+ { \msg_expandable_error:n { Automaton~#1 used~incorrectly. } }
+\cs_new_eq:NN \regex_nfa_end: \scan_stop:
+\prg_new_protected_conditional:Npnn \regex_check_nfa:N #1 { TF }
+ { \exp_after:wN \regex_check_nfa_aux:Nw #1 \q_stop }
+\cs_new:Npn \regex_check_nfa_aux:Nw #1 #2 \q_stop
+ {
+ \if_meaning:w \regex_nfa:Nw #1
+ \prg_return_true:
+ \else:
+ \msg_error:nnx { regex } { not-nfa } { \token_to_str:N #1 }
+ \prg_return_false:
+ \fi:
+ }
+\msg_new:nnn { regex } { not-nfa }
+ {
+ I~was~expecting~a~regular~expression~variable.\\
+ Instead,~I~got~#1.
+ }
+\cs_new_protected_nopar:Npn \regex_use:N #1
+ { \exp_after:wN \use_none:nn #1 }
+\cs_new_protected:Npn \regex_user_aux:n #1
+ {
+ \group_begin:
+ \tl_clear:N \l_regex_every_match_tl
+ #1
+ \group_end:
+ }
+\cs_new_protected_nopar:Npn \regex_return_after_group:
+ {
+ \if_bool:N \l_regex_success_bool
+ \group_insert_after:N \prg_return_true:
+ \else:
+ \group_insert_after:N \prg_return_false:
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \regex_extract_after_group:N #1
+ {
+ \if_bool:N \l_regex_success_bool
+ \regex_extract:
+ \group_insert_after:N \seq_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_submatches_seq
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \regex_count_after_group:N #1
+ {
+ \group_insert_after:N \int_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_match_count_int
+ }
+\prg_new_protected_conditional:Npnn \regex_match:nn #1#2 { T , F , TF }
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_return_after_group:
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_match:Nn #1#2 { T , F , TF }
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_return_after_group:
+ }
+ }
+ { \prg_return_false: }
+ }
+\cs_new_protected:Npn \regex_count:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \int_gzero:N \g_regex_match_count_int
+ \tl_set:Nn \l_regex_every_match_tl
+ {
+ \int_gincr:N \g_regex_match_count_int
+ \regex_match_once:
+ }
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_count_after_group:N #3
+ }
+ }
+\cs_new_protected:Npn \regex_count:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_disable_submatches:
+ \int_gzero:N \g_regex_match_count_int
+ \tl_set:Nn \l_regex_every_match_tl
+ {
+ \int_gincr:N \g_regex_match_count_int
+ \regex_match_once:
+ }
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_count_after_group:N #3
+ }
+ }
+ { }
+ }
+\cs_new_protected:Npn \regex_extract:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_extract:nnN #1#2#3 { T , F , TF }
+ {
+ \regex_user_aux:n
+ {
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ \regex_return_after_group:
+ }
+ }
+\cs_new_protected:Npn \regex_extract:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ }
+ }
+ { }
+ }
+\prg_new_protected_conditional:Npnn \regex_extract:NnN #1#2#3 { T , F , TF }
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_extract_after_group:N #3
+ \regex_return_after_group:
+ }
+ }
+ { \prg_return_false: }
+ }
+\cs_new_protected:Npn \regex_split:nnN #1#2#3
+ {
+ \regex_user_aux:n
+ {
+ \seq_gclear:N \g_regex_split_seq
+ \tl_set:Nn \l_regex_every_match_tl { \regex_split_aux: }
+ \regex_build:n {#1}
+ \regex_match:n {#2}
+ \regex_split_after_group:N #3
+ }
+ }
+\cs_new_protected:Npn \regex_split:NnN #1#2#3
+ {
+ \regex_check_nfa:NTF #1
+ {
+ \regex_user_aux:n
+ {
+ \seq_gclear:N \g_regex_split_seq
+ \tl_set:Nn \l_regex_every_match_tl { \regex_split_aux: }
+ \regex_use:N #1
+ \regex_match:n {#2}
+ \regex_split_after_group:N #3
+ }
+ }
+ { }
+ }
+\cs_new_protected_nopar:Npn \regex_split_aux:
+ {
+ \int_compare:nNnF \l_regex_start_step_int = \l_regex_success_step_int
+ {
+ \regex_extract:
+ \seq_pop:NN \g_regex_submatches_seq \l_regex_tmpa_tl
+ \regex_extract_aux:nTF {0}
+ {
+ \seq_gput_left:Nx \g_regex_submatches_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \l_regex_tmpa_tl }
+ }
+ }
+ { \msg_error:nn { regex } { internal } }
+ \seq_gconcat:NNN \g_regex_split_seq
+ \g_regex_split_seq \g_regex_submatches_seq
+ }
+ \regex_match_once:
+ }
+\cs_new_protected_nopar:Npn \regex_split_after_group:N #1
+ {
+ \int_compare:nNnTF \l_regex_start_step_int = \l_regex_current_step_int
+ {
+ \bool_if:NF \l_regex_success_empty_bool
+ { \seq_gput_right:Nn \g_regex_split_seq { } }
+ }
+ {
+ \seq_gput_right:Nx \g_regex_split_seq
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \int_use:N \l_regex_current_step_int }
+ }
+ }
+ \group_insert_after:N \seq_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_split_seq
+ }
+\cs_new_protected:Npn \regex_replacement:n #1
+ {
+ \str_aux_escape:NNNn
+ \prg_do_nothing:
+ \regex_replacement_escaped:N
+ \regex_replacement_raw:N
+ {#1}
+ \tl_set_eq:NN \l_regex_replacement_tl \g_str_result_tl
+ \tl_set:Nx \l_regex_replacement_tl
+ { \l_regex_replacement_tl \prg_do_nothing: }
+ }
+\cs_new_nopar:Npn \regex_replacement_raw:N { \exp_not:N \prg_do_nothing: }
+\cs_new_nopar:Npn \regex_replacement_escaped:N #1
+ {
+ \if_num:w 9 < 1 #1 \exp_stop_f:
+ \exp_not:N \regex_replacement_escaped_ii:nN {#1}
+ \else:
+ #1
+ \fi:
+ }
+\cs_new_nopar:Npn \regex_replacement_escaped_ii:nN #1#2
+ {
+ \regex_token_if_other_digit:NTF #2
+ { \regex_replacement_escaped_ii:nN {#1#2} }
+ { \exp_not:N \seq_item:Nn \exp_not:N \g_regex_submatches_seq {#1} #2 }
+ }
+\prg_new_conditional:Npnn \regex_token_if_other_digit:N #1 { TF }
+ {
+ \if_num:w 9 < 1 \exp_not:N #1 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \regex_replace_after_group:N #1
+ {
+ \group_insert_after:N \tl_set_eq:NN
+ \group_insert_after:N #1
+ \group_insert_after:N \g_regex_replaced_str
+ }
+\cs_new_protected:Npn \regex_replace_once_aux:Nn #1#2
+ {
+ \group_begin:
+ \regex_replace_after_group:N #1
+ \tl_clear:N \l_regex_every_match_tl
+ #2
+ \exp_args:No \regex_match:n {#1}
+ \regex_extract:
+ \regex_extract_aux:nTF {0}
+ {
+ \tl_gset:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str {0} { \l_regex_tmpa_tl }
+ \l_regex_replacement_tl
+ \str_from_to:Nnn \l_regex_query_str
+ { \l_regex_tmpb_tl } { \c_max_int }
+ }
+ }
+ { \tl_gset_eq:NN \g_regex_replaced_str \l_regex_query_str }
+ \group_end:
+ }
+\cs_new_protected:Npn \regex_replace_once:nnN #1#2#3
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ }
+ }
+\cs_new_protected:Npn \regex_replace_once:NnN #1#2#3
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_replace_once:nnN #1#2#3 {T,F,TF}
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ \regex_return_after_group:
+ }
+ }
+\prg_new_protected_conditional:Npnn \regex_replace_once:NnN #1#2#3 {T,F,TF}
+ {
+ \regex_replace_once_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ \regex_return_after_group:
+ }
+ }
+\cs_new_protected:Npn \regex_replace_all_aux:Nn #1#2
+ {
+ \group_begin:
+ \regex_replace_after_group:N #1
+ \tl_set:Nn \l_regex_every_match_tl { \regex_replace_all_aux: }
+ \tl_gclear:N \g_regex_replaced_str
+ #2
+ \exp_args:No \regex_match:n {#1}
+ \tl_gput_right:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \c_max_int }
+ }
+ \group_end:
+ }
+\cs_new_protected_nopar:Npn \regex_replace_all_aux:
+ {
+ \regex_extract:
+ \regex_extract_aux:nTF {0}
+ {
+ \tl_gput_right:Nx \g_regex_replaced_str
+ {
+ \str_from_to:Nnn \l_regex_query_str
+ { \int_use:N \l_regex_start_step_int }
+ { \l_regex_tmpa_tl }
+ \l_regex_replacement_tl
+ }
+ }
+ { \msg_error:nn { regex } { internal } }
+ \regex_match_once:
+ }
+\cs_new_protected:Npn \regex_replace_all:nnN #1#2#3
+ {
+ \regex_replace_all_aux:Nn #3
+ {
+ \regex_build:n {#1}
+ \regex_replacement:n {#2}
+ }
+ }
+\cs_new_protected:Npn \regex_replace_all:NnN #1#2#3
+ {
+ \regex_replace_all_aux:Nn #3
+ {
+ \regex_use:N #1
+ \regex_replacement:n {#2}
+ }
+ }
+%%
+%%
+%% End of file `l3regex.sty'.
diff --git a/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty
new file mode 100644
index 00000000000..9a69d0da0a6
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/l3experimental/l3str/l3str.sty
@@ -0,0 +1,970 @@
+%%
+%% This is file `l3str.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% l3str.dtx (with options: `package')
+%%
+%% EXPERIMENTAL CODE
+%%
+%% Do not distribute this file without also distributing the
+%% source files specified above.
+%%
+%% Do not distribute a modified version of this file.
+%%
+%% File: l3str.dtx Copyright (C) 2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX3 Project.
+%%
+%% -----------------------------------------------------------------------
+\RequirePackage{expl3}
+\GetIdInfo$Id: l3str.dtx 2895 2011-10-09 15:58:19Z joseph $
+ {L3 Experimental Strings}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\cs_if_exist:NF \cs_if_exist_use:cF
+ {
+ \cs_new:Npn \cs_if_exist_use:cF #1
+ { \cs_if_exist:cTF {#1} { \use:c {#1} } }
+ }
+\cs_if_exist:NF \use_i:nnnnnnnn
+ { \cs_new:Npn \use_i:nnnnnnnn #1#2#3#4#5#6#7#8 {#1} }
+\cs_set:Npn \str_tmp:w #1
+ {
+ \cs_new_protected:cpx { str_#1:Nn } ##1##2
+ { \exp_not:c { tl_#1:Nx } ##1 { \exp_not:N \tl_to_str:n {##2} } }
+ \exp_args:Nc \cs_generate_variant:Nn { str_#1:Nn } { Nx , cn , cx }
+ }
+\str_tmp:w {set}
+\str_tmp:w {gset}
+\str_tmp:w {put_left}
+\str_tmp:w {gput_left}
+\str_tmp:w {put_right}
+\str_tmp:w {gput_right}
+\cs_set_protected_nopar:Npn \str_tmp:w { }
+\tl_new:N \g_str_tmpa_tl
+\tl_new:N \g_str_result_tl
+\int_new:N \l_str_char_int
+\int_new:N \l_str_bytes_int
+\tl_const:Nx \c_backslash_str { \cs_to_str:N \\ }
+\tl_const:Nx \c_lbrace_str { \cs_to_str:N \{ }
+\tl_const:Nx \c_rbrace_str { \cs_to_str:N \} }
+\tl_const:Nx \c_hash_str { \cs_to_str:N \# }
+\tl_const:Nx \c_percent_str { \cs_to_str:N \% }
+\group_begin:
+\char_set_lccode:nn {`\*}{`\ }
+\char_set_lccode:nn {`\A}{`\A}
+\tl_to_lowercase:n {
+ \group_end:
+ \cs_new:Npn \tl_to_other_str:n #1
+ {
+ \exp_after:wN \tl_to_other_str_loop:w \tl_to_str:n {#1} ~ %
+ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_mark \q_stop
+ }
+ \cs_new_nopar:Npn \tl_to_other_str_loop:w
+ #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 \q_stop
+ {
+ \if_meaning:w A #8
+ \tl_to_other_str_end:w
+ \fi:
+ \tl_to_other_str_loop:w
+ #9 #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * \q_stop
+ }
+ \cs_new_nopar:Npn \tl_to_other_str_end:w \fi: #1 \q_mark #2 * A #3 \q_stop
+ { \fi: #2 }
+}
+\cs_new_nopar:Npn \tl_to_other_str:N
+ { \exp_args:No \tl_to_other_str:n }
+\cs_new:Npn \str_sanitize_args:Nn #1 #2
+ {
+ \exp_args:Nf #1
+ { \tl_to_other_str:n {#2} }
+ }
+\cs_new:Npn \str_sanitize_args:Nnn #1#2#3
+ {
+ \exp_args:Nff #1
+ { \tl_to_other_str:n {#2} }
+ { \tl_to_other_str:n {#3} }
+ }
+\cs_new_nopar:Npn \str_length:N { \exp_args:No \str_length:n }
+\cs_new:Npn \str_length:n { \str_sanitize_args:Nn \str_length_unsafe:n }
+\cs_new_nopar:Npn \str_length_unsafe:n #1
+ { \str_length_aux:n { \str_length_loop:NNNNNNNNN #1 } }
+\cs_new:Npn \str_length_ignore_spaces:n #1
+ {
+ \str_length_aux:n
+ { \exp_after:wN \str_length_loop:NNNNNNNNN \tl_to_str:n {#1} }
+ }
+\cs_new:Npn \str_length_aux:n #1
+ {
+ \int_eval:n
+ {
+ #1
+ { X \c_eight } { X \c_seven } { X \c_six }
+ { X \c_five } { X \c_four } { X \c_three }
+ { X \c_two } { X \c_one } { X \c_zero }
+ \q_stop
+ }
+ }
+\cs_set:Npn \str_length_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9
+ {
+ \if_catcode:w X #9
+ \exp_after:wN \use_none_delimit_by_q_stop:w
+ \fi:
+ \c_nine + \str_length_loop:NNNNNNNNN
+ }
+\cs_set_nopar:Npn \str_head:N { \exp_args:No \str_head:n }
+\cs_set:Npn \str_head:n #1
+ {
+ \exp_after:wN \str_head_aux:w
+ \tl_to_str:n {#1}
+ { { } } ~ \q_stop
+ }
+\cs_set_nopar:Npx \str_head_aux:w #1 ~ %
+ { \exp_not:N \use_i_delimit_by_q_stop:nw #1 { ~ } }
+\cs_new:Npn \str_head_ignore_spaces:n #1
+ { \exp_after:wN \use_i_delimit_by_q_stop:nw \tl_to_str:n {#1} { } \q_stop }
+\cs_new_nopar:Npn \str_head_unsafe:n #1
+ { \use_i_delimit_by_q_stop:nw #1 { } \q_stop }
+\cs_new_nopar:Npn \str_tail:N { \exp_args:No \str_tail:n }
+\cs_set:Npn \str_tail:n #1
+ {
+ \exp_after:wN \str_tail_aux:w
+ \reverse_if:N \if_charcode:w
+ \scan_stop: \tl_to_str:n {#1} X X \q_stop
+ }
+\cs_set_nopar:Npn \str_tail_aux:w #1 X #2 \q_stop { \fi: #1 }
+\cs_new:Npn \str_tail_ignore_spaces:n #1
+ {
+ \exp_after:wN \str_tail_aux_ii:w
+ \tl_to_str:n {#1} X { } X \q_stop
+ }
+\cs_new_nopar:Npn \str_tail_unsafe:n #1
+ { \str_tail_aux_ii:w #1 X { } X \q_stop }
+\cs_set_nopar:Npn \str_tail_aux_ii:w #1 #2 X #3 \q_stop { #2 }
+\cs_new:Npn \str_skip_do:nn #1
+ {
+ \int_compare:nNnTF {#1} > \c_seven
+ { \str_skip_aux:nnnnnnnnn }
+ { \str_skip_end:n }
+ {#1}
+ }
+\cs_new:Npn \str_skip_aux:nnnnnnnnn #1#2 #3#4#5#6#7#8#9
+ { \exp_args:Nf \str_skip_do:nn { \int_eval:n { #1 - \c_seven } } {#2} }
+\cs_new:Npn \str_skip_end:n #1
+ {
+ \if_case:w \int_eval:w #1 \int_eval_end:
+ \str_skip_end_ii:nwn { XXXXXXX }
+ \or: \str_skip_end_ii:nwn { XXXXXX }
+ \or: \str_skip_end_ii:nwn { XXXXX }
+ \or: \str_skip_end_ii:nwn { XXXX }
+ \or: \str_skip_end_ii:nwn { XXX }
+ \or: \str_skip_end_ii:nwn { XX }
+ \or: \str_skip_end_ii:nwn { X }
+ \or: \str_skip_end_ii:nwn { }
+ \else: \str_skip_end_ii:nwn { XXXXXXX }
+ \fi:
+ }
+\cs_new:Npn \str_skip_end_ii:nwn #1 #2 \fi: #3
+ { \fi: \use_i:nnnnnnnn {#3} #1 }
+\cs_new:Npn \str_collect_do:nn #1#2
+ { \str_collect_aux:n {#1} { \str_collect_end_iii:nwNNNNNNN {#2} } }
+\cs_new:Npn \str_collect_aux:n #1
+ {
+ \int_compare:nNnTF {#1} > \c_seven
+ { \str_collect_aux:nnNNNNNNN }
+ { \str_collect_end:n }
+ {#1}
+ }
+\cs_new:Npn \str_collect_aux:nnNNNNNNN #1#2 #3#4#5#6#7#8#9
+ {
+ \exp_args:Nf \str_collect_aux:n
+ { \int_eval:n { #1 - \c_seven } }
+ { #2 #3#4#5#6#7#8#9 }
+ }
+\cs_new:Npn \str_collect_end:n #1
+ {
+ \if_case:w \int_eval:w #1 \int_eval_end:
+ \str_collect_end_ii:nwn { {}{}{}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{}{} }
+ \or: \str_collect_end_ii:nwn { {}{} }
+ \or: \str_collect_end_ii:nwn { {} }
+ \or: \str_collect_end_ii:nwn { }
+ \else: \str_collect_end_ii:nwn { {}{}{}{}{}{}{} }
+ \fi:
+ }
+\cs_new:Npn \str_collect_end_ii:nwn #1 #2 \fi: #3
+ { \fi: #3 \q_stop #1 }
+\cs_new:Npn \str_collect_end_iii:nwNNNNNNN #1 #2 \q_stop #3#4#5#6#7#8#9
+ { #1 {#2#3#4#5#6#7#8#9} }
+\cs_new_nopar:Npn \str_item:Nn { \exp_args:No \str_item:nn }
+\cs_new:Npn \str_item:nn #1#2
+ {
+ \exp_args:Nf \tl_to_str:n
+ { \str_sanitize_args:Nn \str_item_unsafe:nn {#1} {#2} }
+ }
+\cs_new:Npn \str_item_ignore_spaces:nn #1
+ { \exp_args:No \str_item_unsafe:nn { \tl_to_str:n {#1} } }
+\cs_new_nopar:Npn \str_item_unsafe:nn #1#2
+ {
+ \exp_args:Nff \str_item_aux:nn
+ { \int_eval:n {#2} }
+ { \str_length_unsafe:n {#1} }
+ #1
+ \q_stop
+ }
+\cs_new_nopar:Npn \str_item_aux:nn #1#2
+ {
+ \int_compare:nNnTF {#1} < \c_zero
+ {
+ \int_compare:nNnTF {#1} < {-#2}
+ { \use_none_delimit_by_q_stop:w }
+ {
+ \str_skip_do:nn { #1 + #2 }
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ }
+ {
+ \int_compare:nNnTF {#1} < {#2}
+ {
+ \str_skip_do:nn {#1}
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ { \use_none_delimit_by_q_stop:w }
+ }
+ }
+\cs_new_nopar:Npn \str_from_to:Nnn { \exp_args:No \str_from_to:nnn }
+\cs_new:Npn \str_from_to:nnn #1#2#3
+ {
+ \exp_args:Nf \tl_to_str:n
+ { \str_sanitize_args:Nn \str_from_to_unsafe:nnn {#1}{#2}{#3} }
+ }
+\cs_new:Npn \str_from_to_ignore_spaces:nnn #1
+ { \exp_args:No \str_from_to_unsafe:nnn { \tl_to_str:n {#1} } }
+\cs_new:Npn \str_from_to_unsafe:nnn #1#2#3 % <string> <from> <to>
+ {
+ \str_aux_eval_args:Nnnn \str_from_to_aux:nnnw
+ { \str_length_unsafe:n {#1} }
+ {#2}
+ {#3}
+ #1
+ \q_stop
+ }
+\cs_new:Npn \str_from_to_aux:nnnw #1#2#3 % <len> <from> <to>
+ {
+ \exp_args:Nf \str_from_to_aux_ii:nnw
+ { \str_aux_normalize_range:nn {#2} {#1} }
+ { \str_aux_normalize_range:nn {#3} {#1} }
+ }
+\cs_new:Npn \str_from_to_aux_ii:nnw #1#2
+ {
+ \str_skip_do:nn {#1}
+ {
+ \exp_args:Nf \str_collect_do:nn
+ { \int_eval:n { #2 - #1 } }
+ { \use_i_delimit_by_q_stop:nw }
+ }
+ }
+\cs_new:Npn \str_aux_eval_args:Nnnn #1#2#3#4
+ {
+ \exp_after:wN #1
+ \exp_after:wN { \int_value:w \int_eval:w #2 \exp_after:wN }
+ \exp_after:wN { \int_value:w \int_eval:w #3 \exp_after:wN }
+ \exp_after:wN { \int_value:w \int_eval:w #4 }
+ }
+\cs_new:Npn \str_aux_normalize_range:nn #1#2
+ {
+ \int_eval:n
+ {
+ \if_num:w #1 < \c_zero
+ \if_num:w #1 < - #2 \exp_stop_f:
+ \c_zero
+ \else:
+ #1 + #2
+ \fi:
+ \else:
+ \if_num:w #1 < #2 \exp_stop_f:
+ #1
+ \else:
+ #2
+ \fi:
+ \fi:
+ }
+ }
+\cs_new_nopar:Npn \str_map_tokens:Nn
+ { \exp_args:No \str_map_tokens:nn }
+\cs_new_nopar:Npn \str_map_tokens:nn
+ { \str_sanitize_args:Nn \str_map_tokens_aux:nn }
+\cs_new:Npn \str_map_tokens_aux:nn #1#2
+ {
+ \str_map_tokens_loop:nN {#2} #1
+ { ? \use_none_delimit_by_q_recursion_stop:w } \q_recursion_stop
+ }
+\cs_new_nopar:Npn \str_map_tokens_loop:nN #1#2
+ {
+ \use_none:n #2
+ #1 #2
+ \str_map_tokens_loop:nN {#1}
+ }
+\cs_new_eq:NN \str_map_break_do:n \use_i_delimit_by_q_recursion_stop:nw
+\prg_new_conditional:Npnn \str_if_eq:NN #1#2 { p , TF , T , F }
+ {
+ \if_int_compare:w \pdftex_strcmp:D { \tl_to_str:N #1 } { \tl_to_str:N #2 }
+ = \c_zero \prg_return_true: \else: \prg_return_false: \fi:
+ }
+\prg_new_conditional:Npnn \str_if_contains_char:NN #1#2 { p , T , F , TF }
+ {
+ \str_map_tokens:Nn #1 { \str_if_contains_char_aux:NN #2 }
+ \prg_return_false:
+ }
+\prg_new_conditional:Npnn \str_if_contains_char:nN #1#2 { p , T , F , TF }
+ {
+ \str_map_tokens:nn {#1} { \str_if_contains_char_aux:NN #2 }
+ \prg_return_false:
+ }
+\cs_new_nopar:Npn \str_if_contains_char_aux:NN #1#2
+ {
+ \if_num:w `#1 = `#2 \exp_stop_f:
+ \str_if_contains_char_end:w
+ \fi:
+ }
+\cs_new_nopar:Npn \str_if_contains_char_end:w \fi: #1 \prg_return_false:
+ { \fi: \prg_return_true: }
+\prg_new_conditional:Npnn \str_if_bytes:N #1 { p , T , F , TF }
+ {
+ \str_map_tokens:Nn #1 { \str_if_bytes_aux:N }
+ \prg_return_true:
+ }
+\cs_new_nopar:Npn \str_if_bytes_aux:N #1
+ {
+ \int_compare:nNnF {`#1} < \c_two_hundred_fifty_six
+ {
+ \use_i_delimit_by_q_recursion_stop:nw
+ { \prg_return_false: \use_none:n }
+ }
+ }
+\prg_new_protected_conditional:Npnn \str_aux_hexadecimal_test:N #1 { TF }
+ {
+ \tl_if_in:onTF { \tl_to_str:n {abcdef} } {#1}
+ {
+ \int_set:Nn \l_str_char_int
+ { \c_sixteen * \l_str_char_int + `#1 - 87 }
+ \prg_return_true:
+ }
+ {
+ \if_num:w \c_fifteen < "1 \exp_not:N #1 \exp_stop_f:
+ \int_set:Nn \l_str_char_int
+ { \c_sixteen * \l_str_char_int + "#1 }
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+ }
+\prg_new_protected_conditional:Npnn \str_aux_octal_test:N #1 { TF }
+ {
+ \if_num:w \c_seven < '1 \exp_not:N #1 \exp_stop_f:
+ \int_set:Nn \l_str_char_int
+ { \c_eight * \l_str_char_int + '#1 }
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_new_protected_nopar:Npn \str_aux_char_if_octal_digit:NTF #1
+ { \tl_if_in:nnTF { 01234567 } {#1} }
+\cs_new_protected:Npn \str_input:Nn #1#2
+ {
+ \str_aux_escape:NNNn \token_to_str:N \token_to_str:N \token_to_str:N {#2}
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected:Npn \str_ginput:Nn #1#2
+ {
+ \str_aux_escape:NNNn \token_to_str:N \token_to_str:N \token_to_str:N {#2}
+ \tl_gset_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_eq:NN \str_aux_escape_unescaped:N \use:n
+\cs_new_eq:NN \str_aux_escape_escaped:N \use:n
+\cs_new_eq:NN \str_aux_escape_raw:N \use:n
+\cs_new_protected:Npn \str_aux_escape:NNNn #1#2#3#4
+ {
+ \group_begin:
+ \cs_set_nopar:Npn \str_aux_escape_unescaped:N { #1 }
+ \cs_set_nopar:Npn \str_aux_escape_escaped:N { #2 }
+ \cs_set_nopar:Npn \str_aux_escape_raw:N { #3 }
+ \int_set:Nn \tex_escapechar:D {92}
+ \tl_gset:Nx \g_str_result_tl { \tl_to_other_str:n {#4} }
+ \tl_gset:Nx \g_str_result_tl
+ {
+ \exp_after:wN \str_aux_escape_loop:N \g_str_result_tl
+ \q_recursion_tail \q_recursion_stop
+ }
+ \group_end:
+ }
+\cs_new_nopar:Npn \str_aux_escape_loop:N #1
+ {
+ \cs_if_exist_use:cF { str_aux_escape_\token_to_str:N #1:w }
+ { \str_aux_escape_unescaped:N #1 }
+ \str_aux_escape_loop:N
+ }
+\cs_new_nopar:cpn { str_aux_escape_ \c_backslash_str :w }
+ \str_aux_escape_loop:N #1
+ {
+ \cs_if_exist_use:cF { str_aux_escape_/\token_to_str:N #1:w }
+ { \str_aux_escape_escaped:N #1 }
+ \str_aux_escape_loop:N
+ }
+\cs_new_eq:cN
+ { str_aux_escape_ \c_backslash_str q_recursion_tail :w }
+ \use_none_delimit_by_q_recursion_stop:w
+\cs_new_eq:cN
+ { str_aux_escape_ / \c_backslash_str q_recursion_tail :w }
+ \use_none_delimit_by_q_recursion_stop:w
+\cs_new_nopar:cpn { str_aux_escape_~:w } { }
+\cs_new_nopar:cpx { str_aux_escape_/a:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^G }
+\cs_new_nopar:cpx { str_aux_escape_/t:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^I }
+\cs_new_nopar:cpx { str_aux_escape_/n:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^J }
+\cs_new_nopar:cpx { str_aux_escape_/f:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^L }
+\cs_new_nopar:cpx { str_aux_escape_/r:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^M }
+\cs_new_nopar:cpx { str_aux_escape_/e:w }
+ { \exp_not:N \str_aux_escape_raw:N \iow_char:N \^^[ }
+\cs_new_nopar:cpn { str_aux_escape_/x:w } \str_aux_escape_loop:N
+ {
+ \if_false: { \fi: }
+ \int_zero:N \l_str_char_int
+ \str_aux_escape_x_test:N
+ }
+\cs_new_protected_nopar:Npx \str_aux_escape_x_test:N #1
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_space_token #1
+ { \exp_not:N \str_aux_escape_x_test:N }
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_lbrace_str #1
+ { \exp_not:N \str_aux_escape_x_braced_loop:N }
+ { \exp_not:N \str_aux_escape_x_unbraced_i:N #1 }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_unbraced_i:N #1
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_unbraced_ii:N }
+ { \str_aux_escape_x_end: #1 }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_unbraced_ii:N #1
+ {
+ \token_if_eq_charcode:NNTF \c_space_token #1
+ { \str_aux_escape_x_unbraced_ii:N }
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_end: }
+ { \str_aux_escape_x_end: #1 }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_aux_escape_x_braced_loop:N #1
+ {
+ \token_if_eq_charcode:NNTF \c_space_token #1
+ { \str_aux_escape_x_braced_loop:N }
+ {
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_aux_escape_x_braced_loop:N }
+ { \str_aux_escape_x_braced_end:N #1 }
+ }
+ }
+\cs_new_protected_nopar:Npx \str_aux_escape_x_braced_end:N #1
+ {
+ \exp_not:N \token_if_eq_charcode:NNTF \c_rbrace_str #1
+ { \exp_not:N \str_aux_escape_x_end: }
+ {
+ \msg_error:nn { str } { x-missing-brace }
+ \exp_not:N \str_aux_escape_x_end: #1
+ }
+ }
+\group_begin:
+ \char_set_catcode_other:N \^^@
+ \cs_new_protected_nopar:Npn \str_aux_escape_x_end:
+ {
+ \group_begin:
+ \char_set_lccode:nn { \c_zero } { \l_str_char_int }
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \tl_gput_right:Nx \g_str_result_tl
+ { \if_false: } \fi:
+ \str_aux_escape_raw:N ^^@
+ \str_aux_escape_loop:N
+ }
+ }
+\group_end:
+\msg_new:nnn { str } { x-missing-brace }
+ {
+ You~wrote~something~like~
+ `\iow_char:N\\x\{ \int_to_hexadecimal:n { \l_str_char_int }'.~
+ The~closing~brace~is~missing.
+ }
+\group_begin:
+ \char_set_catcode_other:n {`\^^@}
+ \cs_new_protected_nopar:Npn \str_aux_convert_store:
+ {
+ \char_set_lccode:nn {\c_zero} {\l_str_char_int}
+ \tl_to_lowercase:n { \tl_gput_right:Nx \g_str_result_tl {^^@} }
+ }
+ \cs_new_protected_nopar:Npn \str_aux_convert_store:NNn #1#2#3
+ {
+ \char_set_lccode:nn {\c_zero} {#3}
+ \tl_to_lowercase:n { #1 #2 {^^@} }
+ }
+\group_end:
+\cs_new_nopar:Npn \str_aux_byte_to_hexadecimal:N #1
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ {
+ \int_to_letter:n { \int_div_truncate:nn {`#1} \c_sixteen }
+ \int_to_letter:n { \int_mod:nn {`#1} \c_sixteen }
+ }
+ { \msg_expandable_error:n { Invalid~byte~`#1'. } }
+ }
+\cs_new_nopar:Npn \str_aux_byte_to_octal:N #1
+ {
+ \int_compare:nNnTF {`#1} < {64}
+ {
+ 0
+ \int_to_letter:n { \int_div_truncate:nn {`#1} \c_eight }
+ \int_to_letter:n { \int_mod:nn {`#1} \c_eight }
+ }
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ { \int_to_octal:n {`#1} }
+ { \msg_expandable_error:n { Invalid~byte~`#1'. } }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_escape_hexadecimal:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_aux_byte_to_hexadecimal:N }
+ }
+\tl_const:Nx \c_str_bytes_escape_name_str
+ { \c_hash_str \c_percent_str \c_lbrace_str \c_rbrace_str () /<>[] }
+\cs_new_protected_nopar:Npn \str_bytes_escape_name:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_escape_name_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_escape_name_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"21}
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_escape_name_str #1
+ { \c_hash_str \str_aux_byte_to_hexadecimal:N #1 }
+ {#1}
+ }
+ }
+ }
+\tl_const:Nx \c_str_bytes_escape_string_str { \c_backslash_str ( ) }
+\cs_new_protected_nopar:Npn \str_bytes_escape_string:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_escape_string_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_escape_string_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"21}
+ { \c_backslash_str \str_aux_byte_to_octal:N #1 }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_backslash_str \str_aux_byte_to_octal:N #1 }
+ {
+ \str_if_contains_char:NNT \c_str_bytes_escape_string_str #1
+ { \c_backslash_str }
+ #1
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_hexadecimal:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \int_zero:N \l_str_char_int
+ \exp_last_unbraced:Nf \str_bytes_unescape_hexadecimal_aux:N
+ { \tl_to_other_str:N #2 } 0
+ \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_hexadecimal_aux:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \str_aux_hexadecimal_test:NTF #1
+ { \str_bytes_unescape_hexadecimal_aux_ii:N }
+ { \str_bytes_unescape_hexadecimal_aux:N }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_hexadecimal_aux_ii:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \str_aux_hexadecimal_test:NTF #1
+ {
+ \str_aux_convert_store:
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_hexadecimal_aux:N
+ }
+ { \str_bytes_unescape_hexadecimal_aux_ii:N }
+ }
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\#}
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_name:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \int_zero:N \l_str_char_int
+ \exp_last_unbraced:Nf \str_bytes_unescape_name_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_name_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \str_aux_hexadecimal_test:NTF #2
+ { \str_bytes_unescape_name_aux_ii:NN #2 }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_hash_str }
+ \str_bytes_unescape_name_aux:wN #2
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_name_aux_ii:NN #1#2
+ {
+ \str_aux_hexadecimal_test:NTF #2
+ {
+ \str_aux_convert_store:
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_name_aux:wN
+ }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_hash_str #1 }
+ \int_zero:N \l_str_char_int
+ \str_bytes_unescape_name_aux:wN #2
+ }
+ }
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\\}
+ \char_set_catcode_other:N \^^J
+ \char_set_catcode_other:N \^^M
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_string:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_bytes_unescape_string_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \int_zero:N \l_str_char_int
+ \str_aux_octal_test:NTF #2
+ { \str_bytes_unescape_string_aux_d:N }
+ {
+ \int_set:Nn \l_str_char_int
+ {
+ \prg_case_str:xxn {#2}
+ {
+ {n} {10}
+ {r} {13}
+ {t} {9}
+ {b} {8}
+ {f} {12}
+ {(} {40}
+ {)} {41}
+ {\c_backslash_str} {92}
+ {^^J} {-1}
+ {^^M} {-1}
+ }
+ {`#2}
+ }
+ \int_compare:nNnF \l_str_char_int = \c_minus_one
+ { \str_aux_convert_store: }
+ \str_bytes_unescape_string_aux:wN
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux_d:N #1
+ {
+ \str_aux_octal_test:NTF #1
+ { \str_bytes_unescape_string_aux_dd:N }
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN #1
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_unescape_string_aux_dd:N #1
+ {
+ \str_aux_octal_test:NTF #1
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN
+ }
+ {
+ \str_aux_convert_store:
+ \str_bytes_unescape_string_aux:wN #1
+ }
+ }
+\tl_const:Nx \c_str_bytes_percent_encode_str { \tl_to_str:n { [] } }
+\tl_const:Nx \c_str_bytes_percent_encode_not_str { \tl_to_str:n { "-.<> } }
+\cs_new_protected_nopar:Npn \str_bytes_percent_encode:NN #1#2
+ {
+ \str_set:Nx #1
+ { \str_map_tokens:Nn #2 \str_bytes_percent_encode_aux:N }
+ }
+\cs_new_nopar:Npn \str_bytes_percent_encode_aux:N #1
+ {
+ \int_compare:nNnTF {`#1} < {"41}
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_percent_encode_not_str #1
+ { #1 }
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ }
+ {
+ \int_compare:nNnTF {`#1} > {"7E}
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ {
+ \str_if_contains_char:NNTF \c_str_bytes_percent_encode_str #1
+ { \c_percent_str \str_aux_byte_to_hexadecimal:N #1 }
+ { #1 }
+ }
+ }
+ }
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\%}
+ \tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected_nopar:Npn \str_bytes_percent_decode:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_bytes_percent_decode_aux:wN
+ { \tl_to_other_str:N #2 }
+ * \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+ \cs_new_protected_nopar:Npn \str_bytes_percent_decode_aux:wN #1 * #2
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \quark_if_recursion_tail_stop:N #2
+ \int_zero:N \l_str_char_int
+ \str_aux_hexadecimal_test:NTF #2
+ { \str_bytes_percent_decode_aux_ii:NN #2 }
+ {
+ \tl_gput_right:Nx \g_str_result_tl { \c_percent_str }
+ \str_bytes_percent_decode_aux:wN #2
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_bytes_percent_decode_aux_ii:NN #1#2
+ {
+ \str_aux_hexadecimal_test:NTF #2
+ {
+ \str_aux_convert_store:
+ \str_bytes_percent_decode_aux:wN
+ }
+ {
+ \tl_gput_right:Nx \g_str_result_tl {#1}
+ \str_bytes_percent_decode_aux:wN #2
+ }
+ }
+\cs_new_protected_nopar:Npn \str_native_from_UTF_viii:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \exp_last_unbraced:Nf \str_native_from_UTF_viii_aux_i:N
+ { \tl_to_other_str:N #2 }
+ \q_recursion_tail \q_recursion_stop
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_native_from_UTF_viii_aux_i:N #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \int_set:Nn \l_str_char_int { `#1 }
+ \str_native_from_UTF_viii_aux_ii:nN {128} \c_one
+ \str_native_from_UTF_viii_aux_ii:nN {64} \c_zero
+ \str_native_from_UTF_viii_aux_ii:nN {32} \c_two
+ \str_native_from_UTF_viii_aux_ii:nN {16} \c_three
+ \str_native_from_UTF_viii_aux_ii:nN {8} \c_four
+ \msg_error:nnx { str } { utf8-invalid-byte } {#1}
+ \use_i:nnn \str_native_from_UTF_viii_aux_i:N
+ \q_stop
+ \str_native_from_UTF_viii_aux_iii:N
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_ii:nN #1#2
+ {
+ \int_compare:nNnTF \l_str_char_int < {#1}
+ {
+ \int_set_eq:NN \l_str_bytes_int #2
+ \use_none_delimit_by_q_stop:w
+ }
+ { \int_sub:Nn \l_str_char_int {#1} }
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_iii:N #1
+ {
+ \int_compare:nNnTF \l_str_bytes_int < \c_two
+ { \str_native_from_UTF_viii_aux_iv: #1 }
+ {
+ \if_meaning:w \q_recursion_tail #1
+ \msg_error:nn { str } { utf8-premature-end }
+ \exp_after:wN \use_none_delimit_by_q_recursion_stop:w
+ \fi:
+ \quark_if_recursion_tail_stop:N #1
+ \tex_multiply:D \l_str_char_int by 64 \scan_stop: % no interface??
+ \int_decr:N \l_str_bytes_int
+ \int_compare:nNnTF {`#1} < {128}
+ { \use_ii:nn }
+ { \int_compare:nNnTF {`#1} < {192} }
+ {
+ \int_add:Nn \l_str_char_int { `#1 - 128 }
+ \str_native_from_UTF_viii_aux_iii:N
+ }
+ {
+ \msg_error:nnx { str } { utf8-missing-byte } {#1}
+ \str_native_from_UTF_viii_aux_i:N #1
+ }
+ }
+ }
+\cs_new_protected_nopar:Npn
+ \str_native_from_UTF_viii_aux_iv:
+ {
+ \int_compare:nNnTF \l_str_bytes_int = \c_zero
+ {
+ \msg_error:nnx { str } { utf8-extra-byte }
+ { \int_eval:n { \l_str_char_int + 128 } }
+ }
+ {
+ \pdftex_if_engine:TF
+ {
+ \int_compare:nNnTF { \l_str_char_int } < { 256 }
+ { \str_aux_convert_store: }
+ {
+ \msg_error:nnx { str } { utf8-pdftex-overflow }
+ { \int_use:N \l_str_char_int }
+ }
+ }
+ { \str_aux_convert_store: }
+ }
+ \str_native_from_UTF_viii_aux_i:N
+ }
+\msg_new:nnn { str } { utf8-invalid-byte }
+ {
+ \int_compare:nNnTF {`#1} < {256}
+ { Byte~number~\int_eval:n {`#1}~invalid~in~utf-8~encoding. }
+ { The~character~number~\int_eval:n {`#1}~is~not~a~byte. }
+ }
+\msg_new:nnn { str } { utf8-missing-byte }
+ { The~byte~number~\int_eval:n {`#1}~is~not~a~valid~continuation~byte. }
+\msg_new:nnn { str } { utf8-extra-byte }
+ { The~byte~number~\int_eval:n {`#1}~is~only~valid~as~a~continuation~byte. }
+\msg_new:nnnn { str } { utf8-premature-end }
+ { Incomplete~last~utf8~character. }
+ {
+ The~sequence~of~byte~that~I~need~to~convert~to~utf8 \
+ ended~before~the~last~character~was~complete.~Perhaps \
+ it~was~mistakenly~truncated?
+ }
+\msg_new:nnn { str } { utf8-pdftex-overflow }
+ { The~character~number~#1~is~too~big~for~pdfTeX. }
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native:NN #1#2
+ {
+ \group_begin:
+ \tl_gclear:N \g_str_result_tl
+ \str_map_tokens:Nn #2 \str_UTF_viii_from_native_aux_i:N
+ \group_end:
+ \tl_set_eq:NN #1 \g_str_result_tl
+ }
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native_aux_i:N #1
+ {
+ \int_set:Nn \l_str_char_int {`#1}
+ \int_compare:nNnTF \l_str_char_int < {128}
+ { \tl_gput_right:Nx \g_str_result_tl {#1} }
+ {
+ \tl_gclear:N \g_str_tmpa_tl
+ \int_set:Nn \l_str_bytes_int { 64 }
+ \str_UTF_viii_from_native_aux_ii:n {32}
+ \str_UTF_viii_from_native_aux_ii:n {16}
+ \str_UTF_viii_from_native_aux_ii:n {8}
+ \ERROR % somehow the unicode char was > "1FFFFF > "10FFFF
+ \tl_gclear:N \g_str_tmpa_tl
+ \use_none:n \q_stop
+ \int_add:Nn \l_str_char_int { 2 * \l_str_bytes_int }
+ \str_aux_convert_store:
+ \tl_gput_right:Nx \g_str_result_tl { \g_str_tmpa_tl }
+ }
+ }
+\cs_new_protected_nopar:Npn \str_UTF_viii_from_native_aux_ii:n #1
+ {
+ \str_aux_convert_store:NNn
+ \tl_gput_left:Nx \g_str_tmpa_tl
+ { 128 + \int_mod:nn { \l_str_char_int } {64} }
+ \tex_divide:D \l_str_char_int by 64 \scan_stop: % no interface??
+ \int_add:Nn \l_str_bytes_int {#1}
+ \int_compare:nNnT \l_str_char_int < {#1}
+ { \use_none_delimit_by_q_stop:w }
+ }
+\cs_gset:Npn \str_length_skip_spaces:N
+ { \exp_args:No \str_length_skip_spaces:n }
+\cs_gset_eq:NN \str_length_skip_spaces:n \str_length_ignore_spaces:n
+%%
+%%
+%% End of file `l3str.sty'.
diff --git a/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty b/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty
index cbadf49e9fb..79490432742 100644
--- a/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty
+++ b/Master/texmf-dist/tex/latex/l3experimental/xcoffins/xcoffins.sty
@@ -47,7 +47,7 @@
%% -----------------------------------------------------------------------
%%
\RequirePackage{xparse}
-\GetIdInfo$Id: xcoffins.dtx 2349 2011-05-11 18:44:37Z joseph $
+\GetIdInfo$Id: xcoffins.dtx 2895 2011-10-09 15:58:19Z joseph $
{L3 Experimental design-level coffins}
\ProvidesExplPackage
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
diff --git a/Master/texmf-dist/tex/latex/l3experimental/xgalley/l3galley.sty b/Master/texmf-dist/tex/latex/l3experimental/xgalley/l3galley.sty
new file mode 100644
index 00000000000..b626f072d30
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/l3experimental/xgalley/l3galley.sty
@@ -0,0 +1,764 @@
+%%
+%% This is file `l3galley.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% l3galley.dtx (with options: `package')
+%%
+%% EXPERIMENTAL CODE
+%%
+%% Do not distribute this file without also distributing the
+%% source files specified above.
+%%
+%% Do not distribute a modified version of this file.
+%%
+%% File: l3galley.dtx Copyright (C) 1999-2001, 2004-2009 Frank Mittelbach
+%% (C) 2010,2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX Project Team.
+%%
+%% -----------------------------------------------------------------------
+%%
+\RequirePackage{l3names}
+\GetIdInfo$Id: l3galley.dtx 2899 2011-10-09 21:22:06Z joseph $
+ {L3 Experimental galley code}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\package_check_loaded_expl:
+\cs_new_protected_nopar:Npn \galley_leave_vmode:
+ { \tex_unhbox:D \c_empty_box }
+\clist_new:N \l_galley_parshape_left_indent_clist
+\clist_new:N \l_galley_parshape_right_indent_clist
+\bool_new:N \l_galley_parshape_multipar_bool
+\bool_new:N \l_galley_parshape_resume_std_bool
+\bool_new:N \l_galley_parshape_fixed_lines_bool
+\int_new:N \l_galley_parshape_std_lines_int
+\cs_new_eq:NN \l_galley_text_width_dim \linewidth
+\cs_new_eq:NN \l_galley_total_left_margin_dim \@totalleftmargin
+\dim_new:N \l_galley_total_right_margin_dim
+\int_new:N \l_galley_interpar_penalty_int
+\skip_new:N \l_galley_interpar_vspace_skip
+\cs_new_eq:NN \l_galley_width_dim \tex_hsize:D
+\bool_new:N \g_galley_begin_level_bool
+\bool_new:N \l_galley_begin_level_bool
+\bool_gset_true:N \g_galley_begin_level_bool
+\bool_new:N \g_galley_omit_next_indent_bool
+\bool_new:N \l_galley_omit_next_indent_bool
+\bool_new:N \g_galley_parshape_set_bool
+\bool_new:N \l_galley_parshape_set_bool
+\bool_new:N \g_galley_nobreak_next_bool
+\bool_new:N \l_galley_nobreak_next_bool
+\tl_new:N \g_galley_par_begin_hook_tl
+\tl_new:N \l_galley_par_begin_hook_tl
+\tl_new:N \g_galley_par_end_hook_tl
+\tl_new:N \l_galley_par_end_hook_tl
+\tl_new:N \g_galley_par_after_hook_tl
+\tl_new:N \l_galley_par_after_hook_tl
+\int_new:N \g_galley_previous_par_lines_int
+\int_new:N \l_galley_previous_par_lines_int
+\tl_new:N \g_galley_restore_running_tl
+\tl_new:N \l_galley_restore_running_tl
+\tl_new:N \g_galley_whatsit_next_tl
+\tl_new:N \l_galley_whatsit_next_tl
+\tl_new:N \g_galley_whatsit_previous_tl
+\tl_new:N \l_galley_whatsit_previous_tl
+\tl_new:N \g_galley_interpar_penalty_user_tl
+\tl_new:N \l_galley_interpar_penalty_user_tl
+\tl_new:N \g_galley_interpar_vspace_user_tl
+\tl_new:N \l_galley_interpar_vspace_user_tl
+\cs_new_protected_nopar:Npn \galley_initialise_variables:
+ {
+ \bool_gset_true:N \g_galley_begin_level_bool
+ \tl_gclear:N \g_galley_interpar_penalty_user_tl
+ \tl_gclear:N \g_galley_interpar_vspace_user_tl
+ \bool_gset_true:N \g_galley_omit_next_indent_bool
+ \bool_gset_false:N \g_galley_nobreak_next_bool
+ \tl_gclear:N \g_galley_par_begin_hook_tl
+ \tl_gclear:N \g_galley_par_end_hook_tl
+ \tl_gclear:N \g_galley_par_after_hook_tl
+ \bool_gset_false:N \g_galley_parshape_set_bool
+ \int_gzero:N \g_galley_previous_par_lines_int
+ \tl_gclear:N \g_galley_restore_running_tl
+ \tl_gclear:N \g_galley_whatsits_previous_tl
+ \tl_gclear:N \g_galley_whatsits_next_tl
+ }
+\cs_new_protected_nopar:Npn \galley_initialise_settings:
+ {
+ \dim_set_eq:NN \l_galley_text_width_dim \l_galley_width_dim
+ \dim_zero:N \l_galley_left_margin_dim
+ \dim_zero:N \l_galley_right_margin_dim
+ \dim_zero:N \l_galley_total_left_margin_dim
+ \dim_zero:N \l_galley_total_right_margin_dim
+ }
+\cs_new_protected_nopar:Npn \galley_save_parameters:
+ {
+ \bool_set_eq:NN \l_galley_begin_level_bool
+ \g_galley_begin_level_bool
+ \tl_set_eq:NN \l_galley_interpar_penalty_user_tl
+ \g_galley_interpar_penalty_user_tl
+ \tl_set_eq:NN \l_galley_interpar_vspace_user_tl
+ \g_galley_interpar_vspace_user_tl
+ \bool_set_eq:NN \l_galley_omit_next_indent_bool
+ \g_galley_omit_next_indent_bool
+ \bool_set_eq:NN \l_galley_nobreak_next_bool
+ \g_galley_nobreak_next_bool
+ \tl_set_eq:NN \l_galley_par_begin_hook_tl
+ \g_galley_par_begin_hook_tl
+ \tl_set_eq:NN \l_galley_par_end_hook_tl
+ \g_galley_par_end_hook_tl
+ \tl_set_eq:NN \l_galley_par_after_hook_tl
+ \g_galley_par_after_hook_tl
+ \bool_set_eq:NN \l_galley_parshape_set_bool
+ \g_galley_parshape_set_bool
+ \int_set_eq:NN \l_galley_previous_par_lines_int
+ \g_galley_previous_par_lines_int
+ \tl_set_eq:NN \l_galley_restore_running_tl
+ \g_galley_restore_running_tl
+ \tl_set_eq:NN \l_galley_whatsits_previous_tl
+ \g_galley_whatsits_previous_tl
+ \tl_set_eq:NN \l_galley_whatsits_next_tl
+ \g_galley_whatsits_next_tl
+ }
+\cs_new_protected_nopar:Npn \galley_restore_parameters:
+ {
+ \bool_gset_eq:NN \g_galley_begin_level_bool
+ \l_galley_begin_level_bool
+ \tl_gset_eq:NN \g_galley_interpar_penalty_user_tl
+ \l_galley_interpar_penalty_user_tl
+ \tl_gset_eq:NN \g_galley_interpar_vspace_user_tl
+ \l_galley_interpar_vspace_user_tl
+ \bool_gset_eq:NN \g_galley_omit_next_indent_bool
+ \l_galley_omit_next_indent_bool
+ \bool_gset_eq:NN \g_galley_nobreak_next_bool
+ \l_galley_nobreak_next_bool
+ \tl_gset_eq:NN \g_galley_par_begin_hook_tl
+ \l_galley_par_begin_hook_tl
+ \tl_gset_eq:NN \g_galley_par_end_hook_tl
+ \l_galley_par_end_hook_tl
+ \tl_gset_eq:NN \g_galley_par_after_hook_tl
+ \l_galley_par_after_hook_tl
+ \bool_gset_eq:NN \g_galley_parshape_set_bool
+ \l_galley_parshape_set_bool
+ \int_gset_eq:NN \g_galley_previous_par_lines_int
+ \l_galley_previous_par_lines_int
+ \tl_gset_eq:NN \g_galley_restore_running_tl
+ \l_galley_restore_running_tl
+ \tl_gset_eq:NN \g_galley_whatsits_previous_tl
+ \l_galley_whatsits_previous_tl
+ \tl_gset_eq:NN \g_galley_whatsits_next_tl
+ \l_galley_whatsits_next_tl
+ }
+\cs_new_protected_nopar:Npn \galley_level:
+ {
+ \galley_save_parameters:
+ \group_begin:
+ \galley_initialise_variables:
+ \galley_initialise_settings:
+ \group_insert_after:N \galley_level_end:
+ }
+\cs_new_protected_nopar:Npn \galley_level_end:
+ {
+ \par
+ \galley_restore_parameters:
+ \group_end:
+ }
+\cs_new_protected_nopar:Npn \galley_std_par:
+ {
+ \mode_if_vertical:TF
+ { \tex_par:D }
+ {
+ \g_galley_par_end_hook_tl
+ \galley_set_measure_and_parshape:
+ \group_begin:
+ \tex_par:D
+ \group_end:
+ \int_gadd:Nn \g_galley_previous_par_lines_int \tex_prevgraf:D
+ }
+ \g_galley_par_after_hook_tl
+ \tl_gclear:N \g_galley_par_after_hook_tl
+ \tex_penalty:D \c_ten_thousand
+ }
+\cs_set_protected_nopar:Npn \par { \galley_std_par: }
+\tl_set:Nn \@par { \galley_std_par: }
+\cs_new_protected_nopar:Npn \galley_display_begin:
+ {
+ \group_begin:
+ \galley_save_parameters:
+ \mode_if_vertical:TF
+ {
+ \galley_display_penalty:N \l_galley_display_begin_par_penalty_tl
+ \galley_display_vspace:N \l_galley_display_begin_par_vspace_tl
+ }
+ {
+ \galley_display_penalty:N \l_galley_display_begin_penalty_tl
+ \galley_display_vspace:N \l_galley_display_begin_vspace_tl
+ }
+ \par
+ }
+\cs_new_protected_nopar:Npn \galley_display_penalty:N #1
+ {
+ \tl_if_empty:NF #1
+ {
+ \tl_gput_right:Nx \g_galley_restore_running_tl
+ {
+ \int_gset:Nn \exp_not:N \g_galley_penalty_int
+ { \int_use:N \g_galley_penalty_int }
+ }
+ \int_gset:Nn \g_galley_penalty_int {#1}
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_display_vspace:N #1
+ {
+ \tl_if_empty:NF #1
+ {
+ \tl_gput_right:Nx \g_galley_restore_running_tl
+ {
+ \skip_gset:Nn \exp_not:N \g_galley_vspace_skip
+ { \skip_use:N \g_galley_vspace_skip }
+ }
+ \skip_gset:Nn \g_galley_vspace_int {#1}
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_display_end:
+ {
+ \par
+ \galley_restore_parameters:
+ \group_end:
+ \group_insert_after:N \group_insert_after:N
+ \group_insert_after:N \galley_display_par_setup:
+ }
+\cs_new_protected_nopar:Npn \galley_display_par_setup:
+ {
+ \bool_gset_false:N \g_galley_omit_next_indent_bool
+ \cs_set_eq:NN \par \galley_display_par:
+ }
+\cs_new_protected_nopar:Npn \galley_display_par:
+ {
+ \cs_set_eq:NN \par \galley_std_par:
+ \mode_if_vertical:TF
+ {
+ \par
+ \bool_gset_false:N \g_galley_omit_next_indent_bool
+ \galley_display_penalty:N \l_galley_display_end_par_penalty_tl
+ \galley_display_vspace:N \l_galley_display_end_par_vspace_tl
+ }
+ {
+ \galley_set_measure_and_parshape:
+ \group_begin:
+ \tex_par:D
+ \group_end:
+ \int_gadd:Nn \g_galley_previous_par_lines_int \tex_prevgraf:D
+ \galley_display_penalty:N \l_galley_display_end_penalty_tl
+ \galley_display_vspace:N \l_galley_display_end_vspace_tl
+ }
+ }
+\cs_undefine:N \everypar
+\newtoks \everypar
+\AtBeginDocument
+ {
+ \tex_everypar:D
+ {
+ \bool_if:NTF \g_galley_begin_level_bool
+ { \galley_start_paragraph_first: }
+ { \galley_start_paragraph_std: }
+ \tex_the:D \everypar
+ }
+ }
+\box_new:N \g_galley_last_box
+\cs_new_protected_nopar:Npn \galley_start_paragraph_std:
+ {
+ \group_begin:
+ \box_gset_to_last:N \g_galley_last_box
+ \tex_par:D
+ \galley_insert_vertical_items:
+ \tex_everypar:D { }
+ \tex_noindent:D
+ \group_end:
+ \int_gzero:N \g_galley_previous_par_lines_int
+ \galley_insert_horizontal_items:
+ \galley_restore_running_parameters:
+ }
+\cs_new_protected_nopar:Npn \galley_start_paragraph_first:
+ {
+ \bool_gset_false:N \g_galley_begin_level_bool
+ \mode_if_horizontal:TF
+ {
+ \group_begin:
+ \box_gset_to_last:N \g_galley_last_box
+ \tex_par:D
+ \galley_insert_vspace:
+ \tex_everypar:D { }
+ \tex_noindent:D
+ \group_end:
+ }
+ { \galley_insert_vspace: }
+ \galley_insert_horizontal_items:
+ \galley_restore_running_parameters:
+ }
+\cs_new_protected_nopar:Npn \galley_insert_vertical_items:
+ {
+ \g_galley_whatsit_previous_tl
+ \tl_gclear:N \g_galley_whatsit_previous_tl
+ \tl_if_empty:NTF \g_galley_interpar_penalty_user_tl
+ {
+ \bool_if:NTF \g_galley_nobreak_next_bool
+ { \tex_penalty:D \c_ten_thousand }
+ { \tex_penalty:D \l_galley_interpar_penalty_int }
+ }
+ {
+ \tex_penalty:D
+ \int_eval:w \g_galley_interpar_penalty_user_tl \int_eval_end:
+ \tl_gclear:N \g_galley_interpar_penalty_user_tl
+ }
+ \bool_gset_false:N \g_galley_nobreak_next_bool
+ \galley_insert_vspace:
+ }
+\cs_new_protected_nopar:Npn \galley_insert_vspace:
+ {
+ \tl_if_empty:NTF \g_galley_interpar_vspace_user_tl
+ { \skip_vertical:N \l_galley_interpar_vspace_skip }
+ {
+ \skip_vertical:n { \g_galley_interpar_vspace_user_tl }
+ \tl_gclear:N \g_galley_interpar_vspace_user_tl
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_insert_horizontal_items:
+ {
+ \g_galley_whatsit_next_tl
+ \tl_gclear:N \g_galley_whatsit_next_tl
+ \bool_if:NT \g_galley_omit_next_indent_bool
+ {
+ \box_if_empty:NF \g_galley_last_box
+ { \hbox_to_wd:nn \l_galley_par_indent_dim { } }
+ }
+ \skip_horizontal:N \l_galley_par_begin_skip
+ \g_galley_par_begin_hook_tl
+ \bool_gset_true:N \g_galley_omit_next_indent_bool
+ }
+\cs_new_protected_nopar:Npn \galley_restore_running_parameters:
+ {
+ \g_galley_restore_running_tl
+ \tl_gclear:N \g_galley_restore_running_tl
+ }
+\cs_new_protected_nopar:Npn \galley_margins_set_absolute:nn #1#2
+ {
+ \dim_set:Nn \l_galley_total_left_margin_dim {#1}
+ \dim_set:Nn \l_galley_total_right_margin_dim {#2}
+ \dim_set:Nn \l_galley_text_width_dim
+ {
+ \l_galley_width_dim
+ - \l_galley_total_left_margin_dim
+ - \l_galley_total_right_margin_dim
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_margins_set_relative:nn #1#2
+ {
+ \dim_add:Nn \l_galley_total_left_margin_dim {#1}
+ \dim_add:Nn \l_galley_total_right_margin_dim {#2}
+ \dim_set:Nn \l_galley_text_width_dim
+ {
+ \l_galley_width_dim
+ - \l_galley_total_left_margin_dim
+ - \l_galley_total_right_margin_dim
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_parshape_fixed_lines:nnn #1#2#3
+ {
+ \bool_gset_true:N \g_galley_parshape_set_bool
+ \bool_set_true:N \l_galley_parshape_fixed_lines_bool
+ \int_set:Nn \l_galley_parshape_std_lines_int {#1}
+ \clist_set:Nn \l_galley_parshape_left_indent_clist {#2}
+ \clist_set:Nn \l_galley_parshape_right_indent_clist {#3}
+ \bool_set_true:N \l_galley_parshape_resume_std_bool
+ }
+\cs_new_protected_nopar:Npn \galley_parshape_multi_par:nnnN #1#2#3#4
+ {
+ \bool_gset_true:N \g_galley_parshape_set_bool
+ \bool_set_true:N \l_galley_parshape_multipar_bool
+ \bool_set_false:N \l_galley_parshape_fixed_lines_bool
+ \int_set:Nn \l_galley_parshape_std_lines_int {#1}
+ \clist_set:Nn \l_galley_parshape_left_indent_clist {#2}
+ \clist_set:Nn \l_galley_parshape_right_indent_clist {#3}
+ \bool_set_eq:NN \l_galley_parshape_resume_std_bool #4
+ }
+\cs_new_protected_nopar:Npn \galley_parshape_single_par:nnnN #1#2#3#4
+ {
+ \bool_gset_true:N \g_galley_parshape_set_bool
+ \bool_set_false:N \l_galley_parshape_multipar_bool
+ \bool_set_false:N \l_galley_parshape_fixed_lines_bool
+ \int_set:Nn \l_galley_parshape_std_lines_int {#1}
+ \clist_set:Nn \l_galley_parshape_left_indent_clist {#2}
+ \clist_set:Nn \l_galley_parshape_right_indent_clist {#3}
+ \bool_set_eq:NN \l_galley_parshape_resume_std_bool #4
+ }
+\cs_generate_variant:Nn \galley_parshape_fixed_lines:nnn { nVV }
+\cs_generate_variant:Nn \galley_parshape_multi_par:nnnN { nVV }
+\cs_generate_variant:Nn \galley_parshape_single_par:nnnN { nVV }
+\cs_new_protected_nopar:Npn \galley_set_measure_and_parshape:
+ {
+ \bool_if:NTF \g_galley_parshape_set_bool
+ {
+ \bool_if:NTF \l_galley_parshape_fixed_lines_bool
+ {
+ \int_compare:nNnTF \g_galley_previous_par_lines_int > \c_zero
+ { \galley_generate_parshape_lines: }
+ { \galley_generate_parshape: }
+ }
+ {
+ \bool_gset_eq:NN \g_galley_parshape_set_bool
+ \l_galley_parshape_multipar_bool
+ \galley_generate_parshape:
+ }
+ }
+ {
+ \tex_global:D \tex_parshape:D
+ \c_one
+ \dim_use:N \l_galley_total_left_margin_dim
+ \c_space_tl
+ \dim_use:N \l_galley_text_width_dim
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_generate_parshape:
+ {
+ \tex_global:D \tex_parshape:D
+ \int_eval:w
+ \l_galley_parshape_std_lines_int +
+ \int_min:nn
+ { \clist_length:N \l_galley_parshape_left_indent_clist }
+ { \clist_length:N \l_galley_parshape_right_indent_clist }
+ \bool_if:NT \l_galley_parshape_resume_std_bool { + 1 }
+ \int_eval_end:
+ \prg_replicate:nn \l_galley_parshape_std_lines_int
+ {
+ \dim_use:N \l_galley_total_left_margin_dim
+ \c_space_tl
+ \dim_use:N \l_galley_text_width_dim
+ \c_space_tl
+ }
+ \galley_set_parshape_map:oo
+ \l_galley_parshape_left_indent_clist
+ \l_galley_parshape_right_indent_clist
+ \bool_if:NT \l_galley_parshape_resume_std_bool
+ {
+ \c_space_tl
+ \dim_use:N \l_galley_total_left_margin_dim
+ \c_space_tl
+ \dim_use:N \l_galley_text_width_dim
+ }
+ }
+\cs_new_nopar:Npn \galley_set_parshape_map:nn #1#2
+ { \galley_set_parshape_map_aux:nw { } #1 , \q_mark #2 , \q_stop }
+\cs_generate_variant:Nn \galley_set_parshape_map:nn { oo }
+\cs_new_nopar:Npn \galley_set_parshape_map_aux:nw
+ #1#2 , #3 \q_mark #4 , #5 \q_stop
+ {
+ \bool_if:nTF { \tl_if_empty_p:n {#3} || \tl_if_empty_p:n {#4} }
+ {
+ #1
+ \dim_eval:n { \l_galley_total_left_margin_dim + ( #2 ) }
+ \c_space_tl
+ \dim_eval:n { \l_galley_text_width_dim - ( ( #2 ) + ( #4 ) ) }
+ }
+ {
+ \galley_set_parshape_map_aux:nw
+ {
+ #1
+ \dim_eval:n { \l_galley_total_left_margin_dim + ( #2 ) }
+ \c_space_tl
+ \dim_eval:n { \l_galley_text_width_dim - ( ( #2 ) + ( #4 ) ) }
+ \c_space_tl
+ }
+ #3 \q_mark #5 \q_stop
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_generate_parshape_lines:
+ {
+ \int_compare:nNnTF \tex_parshape:D > \g_galley_previous_par_lines_int
+ {
+ \tex_global:D \tex_parshape:D
+ \int_eval:w \tex_parshape:D - \g_galley_previous_par_lines_int
+ \int_eval_end:
+ \prg_stepwise_function:nnnN
+ { \g_galley_previous_par_lines_int + \c_one }
+ \c_one \tex_parshape:D \galley_generate_parshape_lines_aux:n
+ }
+ {
+ \bool_gset_false:N \g_galley_parshape_set_bool
+ \tex_global:D \tex_parshape:D
+ \c_one
+ \dim_use:N \l_galley_total_left_margin_dim
+ \c_space_tl
+ \dim_use:N \l_galley_text_width_dim
+ }
+ }
+\cs_new_nopar:Npn \galley_generate_parshape_lines_aux:n #1
+ {
+ \etex_parshapeindent:D #1
+ ~
+ \etex_parshapelength:D #1
+ }
+\cs_new_protected_nopar:Npn \galley_set_user_penalty:n #1
+ { \tl_gset:Nx \g_galley_interpar_penalty_user_tl { \int_eval:n {#1} } }
+\cs_new_protected_nopar:Npn \galley_set_user_vspace:n #1
+ { \tl_gset:Nx \g_galley_interpar_vspace_user_tl { \skip_eval:n {#1} } }
+\dim_set:Nn \parskip \c_zero_dim
+\cs_undefine:N \parskip
+\skip_new:N \parskip
+\cs_new_eq:NN \l_galley_line_left_skip \tex_leftskip:D
+\cs_new_eq:NN \l_galley_line_right_skip \tex_rightskip:D
+\dim_new:N \l_galley_par_begin_skip
+\cs_new_eq:NN \l_galley_par_end_skip \tex_parfillskip:D
+\cs_new_eq:NN \l_galley_par_indent_dim \tex_parindent:D
+\cs_new_eq:NN \l_galley_last_line_fit_int \etex_lastlinefit:D
+\cs_new_protected_nopar:Npn \galley_set_interword_spacing:N #1
+ {
+ \bool_if:NTF #1
+ { % TODO Hook for font changes required!
+ \dim_compare:nNnTF { \tex_fontdimen:D \c_three \tex_font:D }
+ = \c_zero_dim
+ { \tex_spaceskip:D \c_zero_dim }
+ { \tex_spaceskip:D \tex_fontdimen:D \c_two \tex_font:D }
+ }
+ { \tex_spaceskip:D \c_zero_dim }
+ }
+\cs_new_eq:NN \l_galley_binop_penalty_int \tex_binoppenalty:D
+\cs_new_eq:NN \l_galley_double_hyphen_demerits_int \tex_doublehyphendemerits:D
+\cs_new_eq:NN \l_galley_emergency_stretch_skip \tex_emergencystretch:D
+\cs_new_eq:NN \l_galley_final_hyphen_demerits_int \tex_finalhyphendemerits:D
+\cs_new_eq:NN \l_galley_linebreak_badness_int \tex_hbadness:D
+\cs_new_eq:NN \l_galley_linebreak_fuzz_dim \tex_hfuzz:D
+\cs_new_eq:NN \l_galley_linebreak_penalty_int \tex_linepenalty:D
+\cs_new_eq:NN \l_galley_linebreak_pretolerance_int \tex_pretolerance:D
+\cs_new_eq:NN \l_galley_mismatch_demerits_int \tex_adjdemerits:D
+\cs_new_eq:NN \l_galley_relation_penalty_int \tex_relpenalty:D
+\cs_new_eq:NN \l_galley_linebreak_tolerance_int \tex_tolerance:D
+\cs_new_eq:NN \l_galley_broken_penalty_int \tex_brokenpenalty:D
+\cs_new_eq:NN \l_galley_interline_penalty_int \tex_interlinepenalty:D
+\cs_new_eq:NN \l_galley_parbreak_badness_int \tex_vbadness:D
+\cs_new_eq:NN \l_galley_parbreak_fuzz_dim \tex_vfuzz:D
+\cs_new_eq:NN \l_galley_post_display_penalty_int \tex_postdisplaypenalty:D
+\cs_new_eq:NN \l_galley_pre_display_penalty_int \tex_predisplaypenalty:D
+\clist_new:N \l_galley_club_penalties_clist
+\clist_new:N \l_galley_line_penalties_clist
+\cs_new_protected_nopar:Npn \galley_set_display_widow_penalties:n #1
+ {
+ \etex_displaywidowpenalties:D
+ \int_eval:w \clist_length:n {#1} + \c_one \int_eval_end:
+ \clist_map_function:nN {#1} \galley_set_aux:n
+ \c_zero
+ }
+\cs_generate_variant:Nn \galley_set_display_widow_penalties:n { V , v }
+\cs_new_protected_nopar:Npn \galley_set_widow_penalties:n #1
+ {
+ \etex_widowpenalties:D
+ \int_eval:w \clist_length:n {#1} + \c_one \int_eval_end:
+ \clist_map_function:nN {#1} \galley_set_aux:n
+ \c_zero
+ }
+\cs_generate_variant:Nn \galley_set_widow_penalties:n { V , v }
+\cs_new_nopar:Npn \galley_set_aux:n #1 { #1 ~ }
+\cs_new_protected_nopar:Npn \galley_set_club_penalties:n #1
+ {
+ \clist_set:Nn \l_galley_club_penalties_clist {#1}
+ \galley_calc_interline_penalties:
+ }
+\cs_generate_variant:Nn \galley_set_club_penalties:n { V , v }
+\cs_new_protected_nopar:Npn \galley_set_interline_penalties:n #1
+ {
+ \clist_set:Nn \l_galley_line_penalties_clist {#1}
+ \galley_calc_interline_penalties:
+ }
+\cs_generate_variant:Nn \galley_set_interline_penalties:n { V , v }
+\cs_new_protected_nopar:Npn \galley_set_display_club_penalties:n #1
+ {
+ \etex_clubpenalties:D
+ \int_eval:w \clist_length:n {#1} + \c_one \int_eval_end:
+ \clist_map_function:nN {#1} \galley_set_aux:n
+ \c_zero
+ \galley_calc_interline_penalties:
+ }
+\cs_generate_variant:Nn \galley_set_display_club_penalties:n { V , v }
+\cs_new_protected_nopar:Npn \galley_set_interline_penalty:n #1
+ {
+ \int_compare:nNnTF { \etex_interlinepenalties:D \c_zero } = \c_zero
+ {
+ \etex_interlinepenalties:D \c_one \int_eval:w #1 \int_eval_end:
+ \galley_calc_interline_penalties:
+ }
+ {
+ \cs_set_nopar:Npn \galley_set_interline_penalty_aux_ii:n ##1
+ {
+ \int_eval:w
+ \etex_interlinepenalties:D ##1
+ - \etex_interlinepenalties:D \etex_interlinepenalties:D \c_zero
+ + #1
+ \int_eval_end:
+ }
+ \exp_args:Nf \galley_set_interline_penalty_aux:nn
+ { \clist_length:N \l_galley_line_penalties_clist } {#1}
+ }
+ }
+\cs_new_protected_nopar:Npn \galley_set_interline_penalty_aux:nn #1#2
+ {
+ \etex_interlinepenalties:D
+ \etex_interlinepenalties:D \c_zero
+ \prg_stepwise_function:nnnN \c_one \c_one {#1}
+ \galley_set_interline_penalty_aux_i:n
+ \prg_stepwise_function:nnnN { #1 + \c_one } \c_one
+ { \etex_interlinepenalties:D \c_zero - \c_one }
+ \galley_set_interline_penalty_aux_ii:n
+ \int_eval:w #2 \int_eval_end:
+ }
+\cs_new_nopar:Npn \galley_set_interline_penalty_aux_i:n #1
+ { \etex_interlinepenalties:D \int_eval:w #1 \int_eval_end: }
+\cs_new_nopar:Npn \galley_set_interline_penalty_aux_ii:n #1 { }
+\cs_new_protected_nopar:Npn \galley_calc_interline_penalties:
+ {
+ \exp_args:Nff \galley_calc_interline_penalties_aux:nn
+ {
+ \int_eval:n
+ {
+ \int_max:nn
+ {
+ \clist_length:N \l_galley_club_penalties_clist
+ + \c_one
+ }
+ {
+ \int_max:nn
+ {
+ \clist_length:N \l_galley_line_penalties_clist
+ + \c_one
+ }
+ { \etex_clubpenalties:D \c_zero }
+ }
+ }
+ }
+ { \clist_length:N \l_galley_line_penalties_clist }
+ }
+\cs_new_protected_nopar:Npn \galley_calc_interline_penalties_aux:nn
+ #1#2
+ {
+ \etex_interlinepenalties:D #1 ~
+ \prg_stepwise_function:nnnN \c_one \c_one {#2}
+ \galley_calc_interline_penalties_aux_i:n
+ \prg_stepwise_function:nnnN { #2 + \c_one } \c_one { #1 - \c_one }
+ \galley_calc_interline_penalties_aux_ii:n
+ \etex_interlinepenalties:D \etex_interlinepenalties:D \c_zero
+ }
+\cs_new_nopar:Npn \galley_calc_interline_penalties_aux_i:n
+ #1
+ {
+ \int_eval:w
+ \clist_item:Nn \l_galley_line_penalties_clist { #1 - \c_one }
+ + 0 \clist_item:Nn \l_galley_club_penalties_clist
+ { #1 - \c_one }
+ - \etex_clubpenalties:D #1 ~
+ \int_eval_end:
+ }
+\cs_new_nopar:Npn \galley_calc_interline_penalties_aux_ii:n
+ #1
+ {
+ \int_eval:w
+ \etex_interlinepenalties:D \etex_interlinepenalties:D \c_zero
+ + 0 \clist_item:Nn \l_galley_club_penalties_clist
+ { #1 - \c_one }
+ - \etex_clubpenalties:D #1 ~
+ \int_eval_end:
+ }
+\cs_new_protected_nopar:Npn \galley_save_club_penalties:N #1
+ { \clist_set_eq:NN #1 \l_galley_club_penalties_clist }
+\cs_new_protected_nopar:Npn \galley_save_interline_penalties:N #1
+ { \clist_set_eq:NN #1 \l_galley_line_penalties_clist }
+\cs_new_protected_nopar:Npn \galley_save_display_club_penalties:N #1
+ {
+ \clist_set:Nx #1
+ {
+ \prg_stepwise_function:nnnN \c_one \c_one
+ { \etex_clubpenalties:D \c_zero - \c_one }
+ \galley_save_display_club_penalties:_aux:n
+ }
+ }
+\cs_new_nopar:Npn \galley_save_display_club_penalties:_aux:n #1
+ { \int_use:N \etex_clubpenaltes:D \int_eval:w #1 \int_eval_end: , }
+\cs_new_protected_nopar:Npn \galley_save_display_widow_penalties:N #1
+ {
+ \clist_set:Nx #1
+ {
+ \prg_stepwise_function:nnnN \c_one \c_one
+ { \etex_displaywidowpenalties:D \c_zero - \c_one }
+ \galley_save_display_widow_penalties:_aux:n
+ }
+ }
+\cs_new_nopar:Npn \galley_save_display_widow_penalties:_aux:n #1
+ { \int_use:N \etex_displaywidowpenalties:D \int_eval:w #1 \int_eval_end: , }
+\cs_new_protected_nopar:Npn \galley_save_widow_penalties:N #1
+ {
+ \clist_set:Nx #1
+ {
+ \prg_stepwise_function:nnnN \c_one \c_one
+ { \etex_widowpenalties:D \c_zero - \c_one }
+ \galley_save_widow_penalties:_aux:n
+ }
+ }
+\cs_new_nopar:Npn \galley_save_widow_penalties:_aux:n #1
+ { \int_use:N \etex_widowpenalties:D \int_eval:w #1 \int_eval_end: , }
+\cs_new_protected_nopar:Npn \galley_interline_penalty:
+ { \int_use:N \etex_interlinepenalties:D \etex_interlinepenalties:D \c_zero }
+\cs_set_protected_nopar:Npn \@afterheading
+ {
+ \bool_gset_true:N \g_galley_no_break_next_bool
+ \if@afterindent
+ \else
+ \bool_gset_true:N \galley_omit_next_indent_bool
+ \fi
+ }
+\cs_set_protected:Npn \@hangfrom #1
+ {
+ \setbox \@tempboxa = \hbox { {#1} }
+ \galley_parshape_single_par:nnnN
+ \c_one
+ { \box_wd:N \@tempboxa }
+ \c_zero_dim
+ \c_false_bool
+ \bool_gset_true:N \g_galley_no_break_next_bool
+ \bool_gset_true:N \galley_omit_next_indent_bool
+ \box \@tempboxa
+ }
+\cs_set_protected:Npn \@makefntext #1
+ {
+ \UseTemplate { justification } { std } { indent-width = 1 em }
+ \bool_gset_true:N \galley_omit_next_indent_bool
+ \galley_leave_vmode:
+ \hb@xt@ 1.8em { \hss \@makefnmark } #1
+ }
+%%
+%%
+%% End of file `l3galley.sty'.
diff --git a/Master/texmf-dist/tex/latex/l3experimental/xgalley/xgalley.sty b/Master/texmf-dist/tex/latex/l3experimental/xgalley/xgalley.sty
new file mode 100644
index 00000000000..160fca57631
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/l3experimental/xgalley/xgalley.sty
@@ -0,0 +1,616 @@
+%%
+%% This is file `xgalley.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% xgalley.dtx (with options: `package')
+%%
+%% EXPERIMENTAL CODE
+%%
+%% Do not distribute this file without also distributing the
+%% source files specified above.
+%%
+%% Do not distribute a modified version of this file.
+%%
+%% File: xgalley.dtx Copyright (C) 1999-2001, 2004-2009 Frank Mittelbach
+%% (C) 2010,2011 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 released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX Project Team.
+%%
+%% -----------------------------------------------------------------------
+%%
+\RequirePackage{l3names}
+\GetIdInfo$Id: xgalley.dtx 2895 2011-10-09 15:58:19Z joseph $
+ {L3 Experimental galley}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\RequirePackage{xparse,xtemplate,l3galley}
+\clist_new:N \l_galley_tmpa_clist
+\clist_new:N \l_galley_tmpb_clist
+\DeclareObjectType { measure } { 0 }
+\DeclareTemplateInterface { measure } { absolute } { 0 }
+ {
+ left-margin : length = 0 pt ,
+ right-margin : length = 0 pt
+ }
+\DeclareTemplateInterface { measure } { relative } { 0 }
+ {
+ left-margin : length = 0 pt ,
+ right-margin : length = 0 pt
+ }
+\cs_new_eq:NN \l_galley_left_margin_dim \leftmargin
+\cs_new_eq:NN \l_galley_right_margin_dim \rightmargin
+\DeclareTemplateCode { measure } { absolute } { 0 }
+ {
+ left-margin = \l_galley_left_margin_dim ,
+ right-margin = \l_galley_right_margin_dim
+ }
+ {
+ \AssignTemplateKeys
+ \galley_margins_set_absolute:nn \l_galley_left_margin_dim
+ \l_galley_right_margin_dim
+ }
+\DeclareTemplateCode { measure } { relative } { 0 }
+ {
+ left-margin = \l_galley_left_margin_dim ,
+ right-margin = \l_galley_right_margin_dim
+ }
+ {
+ \AssignTemplateKeys
+ \galley_margins_set_relative:nn \l_galley_left_margin_dim
+ \l_galley_right_margin_dim
+ }
+\DeclareObjectType { parshape } { 0 }
+\DeclareTemplateInterface { parshape } { hang } { 0 }
+ {
+ indent : length = 0 pt ,
+ on-left-side : boolean = true ,
+ lines : integer = 1
+ }
+\DeclareTemplateInterface { parshape } { initial } { 0 }
+ {
+ indent : length = 0 pt ,
+ on-left-side : boolean = true ,
+ lines : integer = 2
+ }
+\DeclareTemplateCode { parshape } { hang } { 0 }
+ {
+ indent = \l_galley_parshape_indent_dim ,
+ on-left-side = \l_galley_parshape_on_left_bool ,
+ lines = \l_galley_parshape_lines_int
+ }
+ {
+ \AssignTemplateKeys
+ \bool_if:NTF \l_galley_parshape_on_left_bool
+ {
+ \galley_parshape_single_par:nVVN
+ \l_galley_parshape_lines_int
+ \l_galley_parshape_indent_dim
+ \c_zero_dim
+ \c_false_bool
+ }
+ {
+ \galley_parshape_single_par:nVVN
+ \l_galley_parshape_lines_int
+ \c_zero_dim
+ \l_galley_parshape_indent_dim
+ \c_false_bool
+ }
+ }
+\DeclareTemplateCode { parshape } { initial } { 0 }
+ {
+ indent = \l_galley_parshape_indent_dim ,
+ on-left-side = \l_galley_parshape_on_left_bool ,
+ lines = \l_galley_parshape_lines_int
+ }
+ {
+ \AssignTemplateKeys
+ \clist_clear:N \l_galley_tmpa_clist
+ \clist_clear:N \l_galley_tmpb_clist
+ \prg_replicate:nn { \l_galley_parshape_lines_int }
+ {
+ \clist_put_right:Nn \l_galley_tmpa_clist
+ { \l_galley_parshape_indent_dim }
+ \clist_put_right:Nn \l_galley_tmpb_clist
+ { \c_zero_dim }
+ }
+ \bool_if:NTF \l_galley_parshape_on_left_bool
+ {
+ \galley_parshape_single_par:nVVN
+ \c_zero
+ \l_galley_tmpa_clist
+ \l_galley_tmpb_clist
+ \c_true_bool
+ }
+ {
+ \galley_parshape_single_par:nVVN
+ \c_zero
+ \l_galley_tmpb_clist
+ \l_galley_tmpa_clist
+ \c_true_bool
+ }
+ }
+\DeclareTemplateInterface { parshape } { std } { 0 } { }
+\DeclareTemplateCode { parshape } { std } { 0 } { } { }
+\DeclareObjectType { hyphenation } { 0 }
+\DeclareTemplateInterface { hyphenation } { std } { 0 }
+ {
+ enable : boolean = true ,
+ enable-upper-case : boolean = true ,
+ penalty : choice { low , medium , high } = low
+ }
+\DeclareTemplateCode { hyphenation } { std } { 0 }
+ {
+ enable = \l_galley_hyphen_enable_bool ,
+ enable-upper-case = \l_galley_hyphen_uppercase_bool ,
+ penalty =
+ {
+ low =
+ {
+ \int_set:Nn \tex_hyphenpenalty:D { 51 }
+ \int_set:Nn \tex_exhyphenpenalty:D { 51 }
+ } ,
+ medium =
+ {
+ \int_set:Nn \tex_hyphenpenalty:D { 151 }
+ \int_set:Nn \tex_exhyphenpenalty:D { 151 }
+ } ,
+ high =
+ {
+ \int_set:Nn \tex_hyphenpenalty:D { 301 }
+ \int_set:Nn \tex_exhyphenpenalty:D { 301 }
+ } ,
+ }
+ }
+ {
+ \AssignTemplateKeys
+ \int_set:Nn \tex_lefthyphenmin:D
+ {
+ \bool_if:NTF \l_galley_hyphen_enable_bool
+ { \l_galley_hyphen_left_int } { 63 }
+ }
+ \int_set:Nn \tex_uchyph:D
+ { \bool_if:NTF \l_galley_hyphen_uppercase_bool { 1 } { 0 } }
+ }
+\tex_defaulthyphenchar:D 45 \scan_stop:
+\tl_new:N \l_galley_justification_other_tl
+\DeclareObjectType { justification } { 0 }
+\DeclareTemplateInterface { justification } { std } { 0 }
+ {
+ end-skip : skip = 0 pt plus 1 fil ,
+ fixed-word-spacing : boolean = false ,
+ indent-width : length ,
+ left-skip : skip = 0 pt ,
+ right-skip : skip = 0 pt ,
+ start-skip : skip = 0 pt ,
+ stretch-last-line : boolean = false
+ }
+\DeclareTemplateInterface { justification } { single } { 0 }
+ {
+ end-skip : skip = 0 pt plus 1 fil ,
+ fixed-word-spacing : boolean = false ,
+ indent-width : length ,
+ left-skip : skip = 0 pt ,
+ right-skip : skip = 0 pt ,
+ start-skip : skip = 0 pt ,
+ stretch-last-line : boolean = false
+ }
+\DeclareTemplateCode { justification } { std } { 0 }
+ {
+ end-skip = \l_galley_par_end_skip ,
+ fixed-word-spacing = \l_galley_fixed_spacing_bool ,
+ indent-width = \l_galley_par_indent_dim ,
+ left-skip = \l_galley_line_left_skip ,
+ right-skip = \l_galley_line_right_skip ,
+ start-skip = \l_galley_par_begin_skip ,
+ stretch-last-line = \l_galley_par_stretch_last_bool
+ }
+ {
+ \AssignTemplateKeys
+ \tl_clear:N \l_galley_justification_other_tl
+ \galley_set_interword_spacing:N \l_galley_fixed_spacing_bool
+ \bool_if:NTF \l_galley_par_stretch_last_bool
+ { \int_set_eq:NN \l_galley_last_line_fit_int \c_one_thousand }
+ { \int_zero:N \l_galley_last_line_fit_int }
+ \skip_set:Nn \@rightskip { \l_galley_line_right_skip }
+ }
+\DeclareTemplateCode { justification } { single } { 0 }
+ {
+ end-skip = \l_galley_par_end_skip ,
+ fixed-word-spacing = \l_galley_fixed_spacing_bool ,
+ indent-width = \l_galley_par_indent_dim ,
+ left-skip = \l_galley_line_left_skip ,
+ right-skip = \l_galley_line_right_skip ,
+ start-skip = \l_galley_par_begin_skip ,
+ stretch-last-line = \l_galley_par_stretch_last_bool
+ }
+ {
+ \tl_put_left:Nx \l_galley_justification_other_tl
+ {
+ \skip_set:Nn \exp_not:N \l_galley_par_end_skip
+ { \skip_use:N \l_galley_par_end_skip }
+ \bool_if:NTF \l_galley_fixed_spacing_bool
+ { \bool_set_true:N \exp_not:N \l_galley_fixed_spacing_bool }
+ { \bool_set_false:N \exp_not:N \l_galley_fixed_spacing_bool }
+ \galley_set_interword_space:N
+ \exp_not:N \l_galley_fixed_spacing_bool
+ \dim_set:Nn \exp_not:N \l_galley_par_indent_dim
+ { \dim_use:N \l_galley_par_indent_dim }
+ \skip_set:Nn \l_galley_line_left_skip
+ { \skip_use:N \l_galley_line_left_skip }
+ \skip_set:Nn \exp_not:N \l_galley_line_right_skip
+ { \skip_use:N \l_galley_line_right_skip }
+ \skip_set:Nn \exp_not:N \l_galley_par_start_skip
+ { \skip_use:N \l_galley_par_start_skip }
+ \int_set:Nn \exp_not:N \l_galley_last_line_fit_int
+ { \int_use:N \l_galley_last_line_fit_int }
+ \skip_set:Nn \exp_not:N \@rightskip
+ { \skip_use:N \l_galley_line_right_skip }
+ }
+ \tl_gput_right:Nn \g_galley_restore_running_tl
+ { \l_galley_justification_other_tl }
+ \AssignTemplateKeys
+ \galley_set_interword_spacing:N \l_galley_fixed_spacing_bool
+ \bool_if:NTF \l_galley_par_stretch_last_bool
+ { \int_set_eq:NN \l_galley_last_line_fit_int \c_one_thousand }
+ { \int_zero:N \l_galley_last_line_fit_int }
+ \skip_set:Nn \@rightskip { \l_galley_line_right_skip }
+ }
+\DeclareInstance { justification } { justified } { std }
+ { indent-width = 15 pt }
+\UseInstance { justification } { justified }
+\DeclareInstance { justification } { noindent } { std }
+ {
+ end-skip = 15 pt plus 1 fil ,
+ indent-width = 0 pt
+ }
+\DeclareInstance { justification } { centered } { std }
+ {
+ end-skip = 0 pt ,
+ fixed-word-spacing = true ,
+ indent-width = 0 pt ,
+ left-skip = 0 pt plus 1 em ,
+ right-skip = 0 pt plus 1 em
+ }
+\DeclareInstance { justification } { ragged-left } { std }
+ {
+ end-skip = 0 pt ,
+ fixed-word-spacing = true ,
+ indent-width = 0 pt ,
+ left-skip = 0 pt plus 2 em ,
+ right-skip = 0 pt
+ }
+\DeclareInstance { justification } { ragged-right } { std }
+ {
+ end-skip = 0 pt plus 1 fil ,
+ fixed-word-spacing = true ,
+ indent-width = 0 pt ,
+ left-skip = 0 pt ,
+ right-skip = 0 pt plus 2 em
+ }
+\DeclareInstance { justification } { centering } { std }
+ {
+ end-skip = 0 pt ,
+ fixed-word-spacing = true ,
+ indent-width = 0 pt ,
+ left-skip = 0 pt plus 1 fil ,
+ right-skip = 0 pt plus 1 fil
+ }
+\DeclareTemplateInterface { justification } { compound } { 0 }
+ {
+ first-paragraph : instance { justification } ,
+ other-paragraphs : instance { justification }
+ }
+\DeclareTemplateCode { justification } { compound } { 0 }
+ {
+ first-paragraph = \galley_justification_first: ,
+ other-paragraphs = \galley_justification_other:
+ }
+ {
+ \AssignTemplateKeys
+ \galley_justification_first:
+ \tl_set:Nn \l_galley_justification_other_tl
+ { \galley_justification_other: }
+ \tl_gput_right:Nn \g_galley_restore_running_tl
+ { \l_galley_justification_other_tl }
+ }
+\DeclareObjectType { line-breaking } { 0 }
+\DeclareTemplateInterface { line-breaking } { std } { 0 }
+ {
+ badness : integer = 1000 ,
+ binop-penalty : integer = 700 ,
+ double-hyphen-demerits : integer = 10 000 ,
+ emergency-stretch : skip = 0 pt ,
+ final-hyphen-demerits : integer = 5000 ,
+ fuzz : length = 0.1 pt ,
+ line-penalty : integer = 10 ,
+ mismatch-demerits : integer = 10 000 ,
+ pretolerance : integer = 100 ,
+ relation-penalty : integer = 500 ,
+ tolerance : integer = 200
+ }
+\DeclareTemplateCode{ line-breaking } { std } { 0 }
+ {
+ badness = \l_galley_linebreak_badness_int ,
+ binop-penalty = \l_galley_binop_penalty_int ,
+ double-hyphen-demerits = \l_galley_double_hyphen_demerits_int ,
+ emergency-stretch = \l_galley_emergency_stretch_skip ,
+ final-hyphen-demerits = \l_galley_final_hyphen_demerits_int ,
+ fuzz = \l_galley_linebreak_fuzz_dim ,
+ line-penalty = \l_galley_linebreak_penalty_int ,
+ mismatch-demerits = \l_galley_mismatch_demerits_int ,
+ pretolerance = \l_galley_linebreak_pretolerance_int ,
+ relation-penalty = \l_galley_relation_penalty_int ,
+ tolerance = \l_galley_linebreak_tolerance_int
+ }
+ { \AssignTemplateKeys }
+\DeclareInstance { line-breaking } { std } { std } { }
+\UseInstance { line-breaking } { std }
+\DeclareObjectType { paragraph-breaking } { 0 }
+\DeclareTemplateInterface { paragraph-breaking } { std } { 0 }
+ {
+ badness : integer = 1000 ,
+ broken-penalty : integer = 100 ,
+ club-penalty : integer = 150 ,
+ display-club-penalty : integer = 150 ,
+ display-widow-penalty : integer = 150 ,
+ fuzz : length = 0.1 pt ,
+ interline-penalty : integer = 0 ,
+ post-display-penalty : integer = 0 ,
+ pre-display-penalty : integer = 10 000 ,
+ widow-penalty : integer = 150
+ }
+\DeclareTemplateCode { paragraph-breaking } { std } { 0 }
+ {
+ badness = \l_galley_parbreak_badness_int ,
+ broken-penalty = \l_galley_broken_penalty_int ,
+ club-penalty = \l_galley_club_penalty_int ,
+ display-club-penalty = \l_galley_display_club_penalty_int ,
+ display-widow-penalty = \l_galley_display_widow_penalty_int ,
+ fuzz = \l_galley_parbreak_fuzz_dim ,
+ interline-penalty = \l_galley_interline_penalty_int ,
+ post-display-penalty = \l_galley_post_display_penalty_int ,
+ pre-display-penalty = \l_galley_pre_display_penalty_int ,
+ widow-penalty = \l_galley_widow_penalty_int
+ }
+ {
+ \AssignTemplateKeys
+ \galley_set_club_penalties:V \l_galley_club_penalty_int
+ \galley_set_display_club_penalties:V \l_galley_display_club_penalty_int
+ \galley_set_display_widow_penalties:V \l_galley_display_widow_penalty_int
+ \galley_set_interline_penalty:n \l_galley_interline_penalty_int
+ \galley_set_widow_penalties:V \l_galley_widow_penalty_int
+ }
+\DeclareInstance { paragraph-breaking } { std } { std } { }
+\UseInstance { paragraph-breaking } { std }
+\DeclareInstance { paragraph-breaking } { nobreak } { std }
+ {
+ interline-penalty = 10 000 ,
+ post-display-penalty = 10 000
+ }
+\DeclareInstance { paragraph-breaking } { nolone } { std }
+ {
+ club-penalty = 10 000 ,
+ display-club-penalty = 10 000 ,
+ display-widow-penalty = 10 000 ,
+ widow-penalty = 10 000
+ }
+\DeclareTemplateInterface { paragraph-breaking } { single } { 0 }
+ {
+ badness : tokenlist ,
+ broken-penalty : tokenlist ,
+ club-penalty : tokenlist ,
+ display-club-penalty : tokenlist ,
+ display-widow-penalty : tokenlist ,
+ fuzz : tokenlist ,
+ interline-penalty : tokenlist ,
+ post-display-penalty : tokenlist ,
+ pre-display-penalty : tokenlist ,
+ widow-penalty : tokenlist
+ }
+\DeclareTemplateCode { paragraph-breaking } { single } { 0 }
+ {
+ badness = \l_galley_parbreak_badness_tl ,
+ broken-penalty = \l_galley_broken_penalty_tl ,
+ club-penalty = \l_galley_club_penalties_tl ,
+ display-club-penalty = \l_galley_display_club_penalties_tl ,
+ display-widow-penalty = \l_galley_display_widow_penalties_tl ,
+ fuzz = \l_galley_parbreak_fuzz_tl ,
+ interline-penalty = \l_galley_interline_penalty_tl ,
+ post-display-penalty = \l_galley_post_display_penalty_tl ,
+ pre-display-penalty = \l_galley_pre_display_penalty_tl ,
+ widow-penalty = \l_galley_widow_penalties_tl
+ }
+ {
+ \AssignTemplateKeys
+ \tl_if_empty:NF \l_galley_interline_penalty_tl
+ {
+ \tl_gput_right:Nx \g_galley_par_after_hook_tl
+ {
+ \int_set:Nn \exp_not:N \l_galley_interline_penalty_int
+ { \galley_interline_penalty: }
+ }
+ \int_set:Nn \l_galley_interline_penalty_int
+ { \l_galley_interline_penalty_tl }
+ }
+ \tl_if_empty:NF \l_galley_parbreak_fuzz_tl
+ {
+ \tl_gput_right:Nx \g_galley_par_after_hook_tl
+ {
+ \dim_set:Nn \exp_not:N \l_galley_parbreak_fuzz_dim
+ { \dim_use:N \l_galley_parbreak_fuzz_dim }
+ }
+ \dim_set:Nn \l_galley_parbreak_fuzz_dim { \l_galley_parbreak_fuzz_tl }
+ }
+ \seq_map_inline:Nn \c_galley_parbreak_single_seq
+ {
+ \tl_if_empty:cF { l_galley_ ##1 _tl }
+ {
+ \tl_gput_right:Nx \g_galley_par_after_hook_tl
+ {
+ \int_set:Nn \exp_not:c { l_galley_ ##1 _int }
+ { \int_use:c { l_galley_ ##1 _int } }
+ }
+ \int_set:cn { l_galley_ ##1 _int }
+ { \tl_use:c { l_galley_ ##1 _tl } }
+ }
+ }
+ \seq_map_inline:Nn \c_galley_parbreak_multi_seq
+ {
+ \tl_if_empty:cF { l_galley_ ##1 _tl }
+ {
+ \use:c { galley_save_ ##1 :N } \l_galley_tmpa_clist
+ \tl_gput_right:Nx \g_galley_par_after_hook_tl
+ {
+ \exp_not:c { galley_set_ ##1 :n }
+ { \exp_not:o \l_galley_tmpa_clist }
+ }
+ \use:c { galley_set_ ##1 :v } { l_galley_ ##1 _tl }
+ }
+ }
+ }
+\seq_new:N \c_galley_parbreak_multi_seq
+\seq_gput_right:Nn \c_galley_parbreak_multi_seq { club_penalties }
+\seq_gput_right:Nn \c_galley_parbreak_multi_seq { display_club_penalties }
+\seq_gput_right:Nn \c_galley_parbreak_multi_seq { display_widow_penalties }
+\seq_gput_right:Nn \c_galley_parbreak_multi_seq { widow_penalties }
+\seq_new:N \c_galley_parbreak_single_seq
+\seq_gput_right:Nn \c_galley_parbreak_single_seq { parbreak_badness }
+\seq_gput_right:Nn \c_galley_parbreak_single_seq { broken_penalty }
+\seq_gput_right:Nn \c_galley_parbreak_single_seq { post_display_penalty }
+\seq_gput_right:Nn \c_galley_parbreak_single_seq { pre_display_penalty }
+\DeclareInstance { paragraph-breaking } { single-std } { single } { }
+\DeclareInstance { paragraph-breaking } { single-nobreak } { single }
+ {
+ interline-penalty = 10 000 ,
+ post-display-penalty = 10 000
+ }
+\DeclareInstance { paragraph-breaking } { single-noclub } { single }
+ {
+ club-penalty = 10 000 ,
+ display-club-penalty = 10 000
+ }
+\DeclareInstance { paragraph-breaking } { single-nolone } { single }
+ {
+ club-penalty = 10 000 ,
+ display-club-penalty = 10 000 ,
+ display-widow-penalty = 10 000 ,
+ widow-penalty = 10 000
+ }
+\DeclareInstance { paragraph-breaking } { single-nowidow } { single }
+ {
+ display-widow-penalty = 10 000 ,
+ widow-penalty = 10 000
+ }
+\DeclareObjectType { display-begin } { 0 }
+\DeclareObjectType { display-end } { 0 }
+\DeclareTemplateInterface { display-begin } { std } { 0 }
+ {
+ par-penalty : tokenlist ,
+ par-space : tokenlist ,
+ penalty : tokenlist ,
+ space : tokenlist
+ }
+\DeclareTemplateInterface { display-end } { std } { 0 }
+ {
+ par-penalty : tokenlist ,
+ par-space : tokenlist ,
+ penalty : tokenlist ,
+ space : tokenlist
+ }
+\DeclareTemplateCode { display-begin } { std } { 0 }
+ {
+ par-penalty = \l_galley_display_begin_par_vpenalty_tl ,
+ par-space = \l_galley_display_begin_par_vspace_tl ,
+ penalty = \l_galley_display_begin_vpenalty_tl ,
+ space = \l_galley_display_begin_vspace_tl
+ }
+ {
+ \AssignTemplateKeys
+ \tl_if_empty:NF \l_galley_display_begin_par_vpenalty_tl
+ {
+ \tl_set:Nx \l_galley_display_begin_par_vpenalty_tl
+ { \int_eval:n { \l_galley_display_begin_par_vpenalty_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_begin_par_vspace_tl
+ {
+ \tl_set:Nx \l_galley_display_begin_par_vspace_tl
+ { \skip_eval:n { \l_galley_display_begin_par_vspace_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_begin_vpenalty_tl
+ {
+ \tl_set:Nx \l_galley_display_begin_vpenalty_tl
+ { \int_eval:n { \l_galley_display_begin_vpenalty_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_begin_vspace_tl
+ {
+ \tl_set:Nx \l_galley_display_begin_vspace_tl
+ { \skip_eval:n { \l_galley_display_begin_vspace_tl } }
+ }
+ }
+\DeclareTemplateCode { display-end } { std } { 0 }
+ {
+ par-penalty = \l_galley_display_end_par_vpenalty_tl ,
+ par-space = \l_galley_display_end_par_vspace_tl ,
+ penalty = \l_galley_display_end_vpenalty_tl ,
+ space = \l_galley_display_end_vspace_tl
+ }
+ {
+ \AssignTemplateKeys
+ \tl_if_empty:NF \l_galley_display_end_par_vpenalty_tl
+ {
+ \tl_set:Nx \l_galley_display_end_par_vpenalty_tl
+ { \int_eval:n { \l_galley_display_end_par_vpenalty_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_end_par_vspace_tl
+ {
+ \tl_set:Nx \l_galley_display_end_par_vspace_tl
+ { \skip_eval:n { \l_galley_display_end_par_vspace_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_end_vpenalty_tl
+ {
+ \tl_set:Nx \l_galley_display_end_vpenalty_tl
+ { \int_eval:n { \l_galley_display_end_vpenalty_tl } }
+ }
+ \tl_if_empty:NF \l_galley_display_end_vspace_tl
+ {
+ \tl_set:Nx \l_galley_display_end_vspace_tl
+ { \skip_eval:n { \l_galley_display_end_vspace_tl } }
+ }
+ }
+\RenewDocumentCommand \nobreak { }
+ { \bool_gset_true:N \g_galley_no_break_next_bool }
+\RenewDocumentCommand \noindent { }
+ { \bool_gset_false:N \g_galley_omit_next_indent_bool }
+\RenewDocumentCommand \vspace { s m } { \galley_set_vspace_user:n {#2} }
+%%
+%%
+%% End of file `xgalley.sty'.