summaryrefslogtreecommitdiff
path: root/macros/generic
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-07-22 03:01:06 +0000
committerNorbert Preining <norbert@preining.info>2021-07-22 03:01:06 +0000
commitc43a0b49bea6195daa6423809f4339d538b5c8d9 (patch)
tree88ebc40586174a8ad651baa8020266c4070f39e3 /macros/generic
parentd06b4118c72d0c81fc0760e24add55e808471dbc (diff)
CTAN sync 202107220301
Diffstat (limited to 'macros/generic')
-rw-r--r--macros/generic/texdimens/README.md258
-rw-r--r--macros/generic/texdimens/texdimens.sty2
-rw-r--r--macros/generic/texdimens/texdimens.tex308
-rw-r--r--macros/generic/xstring/README4
-rw-r--r--macros/generic/xstring/test_etex.pdfbin99780 -> 99781 bytes
-rw-r--r--macros/generic/xstring/test_latex.pdfbin150611 -> 155263 bytes
-rw-r--r--macros/generic/xstring/xstring-en.pdfbin187648 -> 199536 bytes
-rw-r--r--macros/generic/xstring/xstring-en.tex2
-rw-r--r--macros/generic/xstring/xstring-fr.pdfbin201920 -> 215317 bytes
-rw-r--r--macros/generic/xstring/xstring-fr.tex2
-rw-r--r--macros/generic/xstring/xstring.tex343
11 files changed, 527 insertions, 392 deletions
diff --git a/macros/generic/texdimens/README.md b/macros/generic/texdimens/README.md
index 4f028fe689..d574ae2ae6 100644
--- a/macros/generic/texdimens/README.md
+++ b/macros/generic/texdimens/README.md
@@ -10,7 +10,7 @@ LPPL 1.3c. See file LICENSE.md.
Development: https://github.com/jfbu/texdimens
-Release: `0.9delta 2021/07/15`
+Release: `0.9 2021/07/21`
## Aim of this package
@@ -46,24 +46,24 @@ of one TeX point `1pt`, or rather `1pt` is represented internally as `65536`.
If `\foo` is a dimen register:
-- `\number\foo` produces the integer `N` such as `\foo` is the same as `N sp`,
+- `\number\foo` produces the integer `N` such as `\foo` is the same as `Nsp`,
- inside `\numexpr`, `\foo` is replaced by `N`,
- `\the\foo` produces a decimal `D` (with at most five places) followed
-with `pt` (catcode 12 tokens) and this output `D pt` can serve as input
+with `pt` (catcode 12 tokens) and this output `Dpt` can serve as input
in a dimen assignment to produce the same dimension as `\foo`. One can
also use the catcode 11 characters `pt` for this. Digits and decimal
mark must have their standard catcode 12.
-When TeX encounters a dimen denotation of the type `D pt` it will
+When TeX encounters a dimen denotation of the type `Dpt` it will
compute `N` in a way equivalent to `N = round(65536 D)` where ties are
rounded away from zero. Only 17 decimal places of `D` are
kept as it can be shown that going beyond can not change the result.
-When `\foo` has been assigned as `D pt`, `\the\foo` will produce some
-`E pt` where `E` is not necessarily the same as `D`. But it is guaranteed
-that `E pt` defines the same dimension as `D pt̀`.
+When `\foo` has been assigned as `Dpt`, `\the\foo` will produce some
+`Ept` where `E` is not necessarily the same as `D`. But it is guaranteed
+that `Ept` defines the same dimension as `Dpt̀`.
## Further units known to TeX on input
@@ -100,8 +100,8 @@ among those listed above, it first handles `U` as with the `pt` unit.
This means that it computes `N = round(65536*U)`. It then multiplies
this `N` by the conversion factor `phi` and truncates towards zero the
mathematically exact result to obtain an integer `T`:
-`T=trunc(N*phi)`. The assignment `U uu` is concluded by defining the
-value of the dimension to be `T sp`.
+`T=trunc(N*phi)`. The assignment `Uuu` is concluded by defining the
+value of the dimension to be `Tsp`.
Attention that although the mnemotic is `phi=1uu/1pt`, this formula
definitely does not apply with numerator and denominator interpreted as
@@ -129,7 +129,7 @@ between attainable dimensions is `72--73sp` for the `in` and `28--29sp`
for the `cm`, and as `1in` differs internally from `2.54cm` by only
`12sp` (see below the `xintsession` verbatim) it is impossible to adjust
either the `in` side or the `cm` side to obtain equality. See in the
-[TODO] section the closest dimension attainable both via `in` and via
+[Extras?] section the closest dimension attainable both via `in` and via
`cm`.
In particular `1in==2.54cm` is **false** in TeX, but it is true that
@@ -152,19 +152,19 @@ In particular `1in==2.54cm` is **false** in TeX, but it is true that
other units the maximal attainable dimensions in `sp` unit are given in
the middle column of the next table.
- maximal allowed the corresponding minimal TeX dimen denotation
- (with 5 places) maximal attainable dim. causing "Dimension too large"
- --------------- -------------------------- --------------------------
- 16383.99999 pt 1073741823 sp (=\maxdimen) 16383.99999237060546875 pt
- 16322.78954 bp 1073741823 sp (=\maxdimen) 16322.78954315185546875 bp
- 15355.51532 nd 1073741823 sp (=\maxdimen) 15355.51532745361328125 nd
- 15312.02584 dd 1073741822 sp 15312.02584075927734375 dd
- 5758.31742 mm 1073741822 sp 5758.31742095947265625 mm
- 1365.33333 pc 1073741820 sp 1365.33333587646484375 pc
- 1279.62627 nc 1073741814 sp 1279.62627410888671875 nc
- 1276.00215 cc 1073741821 sp 1276.00215911865234375 cc
- 575.83174 cm 1073741822 sp 575.83174896240234375 cm
- 226.70540 in 1073741768 sp 226.70540618896484375 in
+ maximal allowed the corresponding minimal TeX dimen denotation
+ (with 5 places) maximal attainable dim. causing "Dimension too large"
+ --------------- ------------------------- --------------------------
+ 16383.99999pt 1073741823sp (=\maxdimen) 16383.99999237060546875pt
+ 16322.78954bp 1073741823sp (=\maxdimen) 16322.78954315185546875bp
+ 15355.51532nd 1073741823sp (=\maxdimen) 15355.51532745361328125nd
+ 15312.02584dd 1073741822sp 15312.02584075927734375dd
+ 5758.31742mm 1073741822sp 5758.31742095947265625mm
+ 1365.33333pc 1073741820sp 1365.33333587646484375pc
+ 1279.62627nc 1073741814sp 1279.62627410888671875nc
+ 1276.00215cc 1073741821sp 1276.00215911865234375cc
+ 575.83174cm 1073741822sp 575.83174896240234375cm
+ 226.70540in 1073741768sp 226.70540618896484375in
Perhaps for these various peculiarities with dimensional units, TeX does
not provide an output facility for them similar to what `\the` achieves for
@@ -173,11 +173,11 @@ the `pt`.
## Macros of this package
The macros defined by the package are expandable, and will expand
-completely in an `\edef`, or in a `\dimexpr...\relax` construc.
+completely in an `\edef`, or in a `\dimexpr...\relax` construct.
As they parse their inputs via `\dimexpr` they can be nested (with
-suitable postfix dimension unit added to inner macro).
+the suitable dimension unit added as postfix to nested macro).
-Apart for the `\texdimin<uu>up` in case of a negative input, they will
+Apart from the `\texdimen<uu>up` in case of a negative input, they will
even expand completely under f-expansion.
Negative dimensions behave as if replaced by their absolute value, then
@@ -187,67 +187,67 @@ at last step the sign (if result is not zero) is applied (so "down" means
1. For input `X` equal to (or sufficiently close to) `\maxdimen` and
those units `uu` for which `\maxdimen` is not exactly representable
(i.e. all units except `pt`, `bp` and `nd`), the output `D` of the
- "up" macros `\texdimin<uu>up{X}`, if used as `Duu` in a dimension
+ "up" macros `\texdimen<uu>up{X}`, if used as `Duu` in a dimension
assignment or expression, will (naturally) trigger a "Dimension too
large" error.
2. For `dd`, `nc` and `in`, and input `X` equal to (or sufficiently
- close to) `\maxdimen` it turns out that `\texdimin<uu>{X}` produces
+ close to) `\maxdimen` it turns out that `\texdimen<uu>{X}` produces
an output `D` such that `Duu` is the first "virtually attainable" TeX
dimension *beyond* `\maxdimen`. Hence `Duu` will trigger on use
"Dimension too large error".
3. Again for the `dd`, `nc` and `in` units, both the "down" and "up" macros
will trigger "Dimension too large" during their execution if used
- with an input equal to (or sufficiently close to `\maxdimen`.
+ with an input equal to (or sufficiently close to) `\maxdimen`.
-`\texdiminpt{<dim. expr.>}`
+`\texdimenpt{<dim. expr.>}`
> Does `\the\dimexpr <dim. expr.> \relax` then removes the `pt`.
-`\texdiminbp{<dim. expr.>}`
+`\texdimenbp{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D bp`
+> Produces a decimal (with up to five decimal places) `D` such that `Dbp`
> represents the dimension exactly if possible. If not possible it
> will differ by `1sp` from the original dimension, but it is not
> known in advance if it will be above or below.
> `\maxdimen` on input produces `16322.78954` and indeed is realized as `16322.78954bp`.
-`\texdiminbpdown{<dim. expr.>}`
+`\texdimenbpdown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D bp`
+> Produces a decimal (with up to five decimal places) `D` such that `Dbp`
> represents the dimension exactly if possible. If not possible it
> will be smaller by `1sp` from the original dimension.
-`\texdiminbpup{<dim. expr.>}`
+`\texdimenbpup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D bp`
+> Produces a decimal (with up to five decimal places) `D` such that `Dbp`
> represents the dimension exactly if possible. If not possible it
> will be larger by `1sp` from the original dimension.
-`\texdiminnd{<dim. expr.>}`
+`\texdimennd{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D nd`
+> Produces a decimal (with up to five decimal places) `D` such that `Dnd`
> represents the dimension exactly if possible. If not possible it
> will differ by `1sp` from the original dimension, but it is not
> known in advance if it will be above or below.
> `\maxdimen` on input produces `15355.51532` and indeed is realized as `15355.51532nd`.
-`\texdiminnddown{<dim. expr.>}`
+`\texdimennddown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D nd`
+> Produces a decimal (with up to five decimal places) `D` such that `Dnd`
> represents the dimension exactly if possible. If not possible it
> will be smaller by `1sp` from the original dimension.
-`\texdiminndup{<dim. expr.>}`
+`\texdimenndup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D nd`
+> Produces a decimal (with up to five decimal places) `D` such that `Dnd`
> represents the dimension exactly if possible. If not possible it
> will be larger by `1sp` from the original dimension.
-`\texdimindd{<dim. expr.>}`
+`\texdimendd{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D dd`
+> Produces a decimal (with up to five decimal places) `D` such that `Ddd`
> represents the dimension exactly if possible. If not possible it
> will differ by `1sp` from the original dimension, but it is not
> known in advance if it will be above or below.
@@ -256,21 +256,21 @@ at last step the sign (if result is not zero) is applied (so "down" means
> will trigger "Dimension too large" error.
> `\maxdimen-1sp` is attainable via `15312.02584dd`.
-`\texdimindddown{<dim. expr.>}`
+`\texdimendddown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D dd`
+> Produces a decimal (with up to five decimal places) `D` such that `Ddd`
> represents the dimension exactly if possible. If not possible it
> will be smaller by `1sp` from the original dimension.
-`\texdiminddup{<dim. expr.>}`
+`\texdimenddup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D dd`
+> Produces a decimal (with up to five decimal places) `D` such that `Ddd`
> represents the dimension exactly if possible. If not possible it
> will be larger by `1sp` from the original dimension.
-`\texdiminmm{<dim. expr.>}`
+`\texdimenmm{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D mm`
+> Produces a decimal (with up to five decimal places) `D` such that `Dmm`
> represents the dimension exactly if possible. If not possible it
> will either be the closest from below or from above, but it is not
> known in advance which one (and it is not known if the other choice
@@ -279,21 +279,21 @@ at last step the sign (if result is not zero) is applied (so "down" means
> `\maxdimen` as input produces on output `5758.31741` and indeed the
> maximal attainable dimension is `5758.31741mm` (`1073741822sp`).
-`\texdiminmmdown{<dim. expr.>}`
+`\texdimenmmdown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D mm`
+> Produces a decimal (with up to five decimal places) `D` such that `Dmm`
> represents the dimension exactly if possible. If not possible it
> will be largest representable dimension smaller than the original one.
-`\texdiminmmup{<dim. expr.>}`
+`\texdimenmmup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D mm`
+> Produces a decimal (with up to five decimal places) `D` such that `Dmm`
> represents the dimension exactly if possible. If not possible it
> will be smallest representable dimension larger than the original one.
-`\texdiminpc{<dim. expr.>}`
+`\texdimenpc{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D pc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dpc`
> represents the dimension exactly if possible. If not possible it
> will be the closest representable one (in case of tie, the approximant
> from above is chosen).
@@ -301,21 +301,21 @@ at last step the sign (if result is not zero) is applied (so "down" means
> `\maxdimen` as input produces on output `1365.33333` and indeed the
> maximal attainable dimension is `1365.33333pc` (`1073741820sp`).
-`\texdiminpcdown{<dim. expr.>}`
+`\texdimenpcdown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D pc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dpc`
> represents the dimension exactly if possible. If not possible it
> will be largest representable dimension smaller than the original one.
-`\texdiminpcup{<dim. expr.>}`
+`\texdimenpcup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D pc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dpc`
> represents the dimension exactly if possible. If not possible it
> will be smallest representable dimension larger than the original one.
-`\texdiminnc{<dim. expr.>}`
+`\texdimennc{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D nc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dnc`
> represents the dimension exactly if possible. If not possible it
> will either be the closest from below or from above, but it is not
> known in advance which one (and it is not known if the other choice
@@ -325,21 +325,21 @@ at last step the sign (if result is not zero) is applied (so "down" means
> will trigger "Dimension too large" error.
> `\maxdimen-9sp` is attainable via `1279.62627nc`.
-`\texdiminncdown{<dim. expr.>}`
+`\texdimenncdown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D nc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dnc`
> represents the dimension exactly if possible. If not possible it
> will be largest representable dimension smaller than the original one.
-`\texdiminncup{<dim. expr.>}`
+`\texdimenncup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D nc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dnc`
> represents the dimension exactly if possible. If not possible it
> will be smallest representable dimension larger than the original one.
-`\texdimincc{<dim. expr.>}`
+`\texdimencc{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D cc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dcc`
> represents the dimension exactly if possible. If not possible it
> will either be the closest from below or from above, but it is not
> known in advance which one (and it is not known if the other choice
@@ -348,21 +348,21 @@ at last step the sign (if result is not zero) is applied (so "down" means
> `\maxdimen` as input produces on output `1276.00215` and indeed the
> maximal attainable dimension is `1276.00215cc` (`1073741821sp`).
-`\texdiminccdown{<dim. expr.>}`
+`\texdimenccdown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D cc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dcc`
> represents the dimension exactly if possible. If not possible it
> will be largest representable dimension smaller than the original one.
-`\texdiminccup{<dim. expr.>}`
+`\texdimenccup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D cc`
+> Produces a decimal (with up to five decimal places) `D` such that `Dcc`
> represents the dimension exactly if possible. If not possible it
> will be smallest representable dimension larger than the original one.
-`\texdimincm{<dim. expr.>}`
+`\texdimencm{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D cm`
+> Produces a decimal (with up to five decimal places) `D` such that `Dcm`
> represents the dimension exactly if possible. If not possible it
> will either be the closest from below or from above, but it is not
> known in advance which one (and it is not known if the other choice
@@ -371,21 +371,21 @@ at last step the sign (if result is not zero) is applied (so "down" means
> `\maxdimen` as input produces on output `575.83174` and indeed the
> maximal attainable dimension is `575.83174cm` (`1073741822sp`).
-`\texdimincmdown{<dim. expr.>}`
+`\texdimencmdown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D cm`
+> Produces a decimal (with up to five decimal places) `D` such that `Dcm`
> represents the dimension exactly if possible. If not possible it
> will be largest representable dimension smaller than the original one.
-`\texdimincmup{<dim. expr.>}`
+`\texdimencmup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D cm`
+> Produces a decimal (with up to five decimal places) `D` such that `Dcm`
> represents the dimension exactly if possible. If not possible it
> will be smallest representable dimension larger than the original one.
-`\texdiminin{<dim. expr.>}`
+`\texdimenin{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D in`
+> Produces a decimal (with up to five decimal places) `D` such that `Din`
> represents the dimension exactly if possible. If not possible it
> will either be the closest from below or from above, but it is not
> known in advance which one (and it is not known if the other choice
@@ -395,18 +395,54 @@ at last step the sign (if result is not zero) is applied (so "down" means
> will trigger "Dimension too large" error.
> `\maxdimen-55sp` is maximal attainable dimension (via `226.7054in`).
-`\texdiminindown{<dim. expr.>}`
+`\texdimenindown{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D in`
+> Produces a decimal (with up to five decimal places) `D` such that `Din`
> represents the dimension exactly if possible. If not possible it
> will be largest representable dimension smaller than the original one.
-`\texdimininup{<dim. expr.>}`
+`\texdimeninup{<dim. expr.>}`
-> Produces a decimal (with up to five decimal places) `D` such that `D in`
+> Produces a decimal (with up to five decimal places) `D` such that `Din`
> represents the dimension exactly if possible. If not possible it
> will be smallest representable dimension larger than the original one.
+`\texdimenbothcmin{<dim. expr.>}` (new with `0.9dev`)
+
+> Produces a decimal (with up to five decimal places) `D` such that `Din`
+> is the largest dimension smaller than the original one and
+> exactly representable both in the `in` and `cm` units.
+
+`\texdimenbothincm{<dim. expr.>}` (new with `0.9dev`)
+
+> Produces a decimal (with up to five decimal places) `D` such that `Dcm`
+> is the largest dimension smaller than the original one and
+> exactly representable both in the `in` and `cm` units. It thus represents
+> the same dimension as `\texdimenbothcmin{<dim. expr.>}in`.
+
+`\texdimenbothcminpt{<dim. expr.>}` (new with `0.9dev`)
+
+> Produces a decimal (with up to five decimal places) `D` such that `Dpt`
+> is the largest dimension smaller than the original one and
+> exactly representable both in the `in` and `cm` units. It thus represents
+> the same dimension as the one provided by `\texdimenbothcmin` and
+> `\texdimenbothincm`.
+
+`\texdimenbothincmpt{<dim. expr.>}` (new with `0.9dev`)
+
+> Same as `\texdimenbothcminpt`.
+
+`\texdimenbothcminsp{<dim. expr.>}` (new with `0.9dev`)
+
+> Produces an integer (explicit digit tokens) `N` such that `Nsp`
+> is the largest dimension smaller than the original one and
+> exactly representable both in the `in` and `cm` units.
+
+`\texdimenbothincmsp{<dim. expr.>}` (new with `0.9dev`)
+
+> Same as `\texdimenbothcminsp`.
+
+
## Extras?
As already stated the "up" and also the "down" macros for the `dd`, `nc`
@@ -418,46 +454,28 @@ some demand for it.
But of course anyhow the output from the "up" macros if used
as input with the corresponding unit will be beyond `\maxdimen` if the
-latter is not atteignable, i.e. for all units except `bp`, and `nd`
+latter is not attainable, i.e. for all units except `bp`, and `nd`
(and `pt` but there is no "up" macro for it).
-Provide a macro `\texdimforbothincm{<dim.expr.>}` which would output
-the nearest dimension simultaneously representable both in `in` and in
-`cm`?
-
According to a reference on the web by an anonymous contributor the
dimensions representable with both `in` and `cm` units have the shape
-`trunc(3613.5*k) sp` for some integer `k`. So we basically may have a
-delta up to about `1800sp` which is about `0.0275pt` and is still small
-(less than one hundredth of a millimeter, i.e. less than ten micron),
-so perhaps such a utility for
-"safe dimensions" may be useful. Here are for example the dimensions
-nearest to `1in` and realizable both in `in` and `cm` units:
-
- >>> \input texdimens.tex\relax
- (executing \input texdimens.tex\relax in background)
- (./texdimens.tex)
- >>> &exact
- exact mode (floating point evaluations use 16 digits)
- >>> (\texdiminin{4737298sp});
- @_10 1.00021
- >>> (\texdimincm{4737298sp});
- @_11 2.54054
- >>> (\dimexpr1.00021in, \dimexpr2.54054cm);
- @_12 4737298, 4737298
- >>> (\texdiminin{4733685sp});
- @_13 0.99945
- >>> (\texdimincm{4733685sp});
- @_14 2.5386
- >>> (\dimexpr0.99945in, \dimexpr2.5386cm);
- @_15 4733685, 4733685
-
-As promised, one of them, the upper approximation, is at less than
-one hundredth of millimeter from the two nearby targets.
-
-Simpler however and more efficient
-would be for people to finally adopt the French revolution Système
-Métrique (rather than setting up giant financial paradises).
+`trunc(3613.5*k)sp` for some integer `k`. The largest one smaller
+than a given dimension will thus differ from it by at most about `0.055pt`,
+which is also about `0.02mm`.
+
+For example `\texdimenbothincm{1cm}` expands to `0.99994cm` which maps
+internally to `1864566sp` which differs from TeX's `1cm` by only
+`-113sp`. It can be obtained from `0.39368in` or `28.45102pt`.
+
+And `\texdimenbothcmin{1in}` expands to `0.99945in`, maps internally to
+`4733685sp` which differs from TeX's `1in` by `-2601sp`. It can be obtained
+as `2.5386cm` or `72.2303pt`.
+
+Currently the package does not provide analogous approximations from above.
+For the `1in` for example it would be `4737298sp`, i.e. `1.00021in` which
+differs from TeX's `1in` by `+1012sp` and is obtained also as `2.54054cm`
+and `72.28543pt`.
+
<!--
-->
diff --git a/macros/generic/texdimens/texdimens.sty b/macros/generic/texdimens/texdimens.sty
index dbf39c72f8..8467e69a6f 100644
--- a/macros/generic/texdimens/texdimens.sty
+++ b/macros/generic/texdimens/texdimens.sty
@@ -1,5 +1,5 @@
% This is file texdimens.tex, part of texdimens package, which
% is distributed under the LPPL 1.3c. Copyright (c) 2021 Jean-François Burnol
-\ProvidesPackage{texdimens}[2021/07/15 v0.9delta conversion of TeX dimensions to decimals (JFB)]
+\ProvidesPackage{texdimens}[2021/07/21 v0.9 conversion of TeX dimensions to decimals (JFB)]
\@@input texdimens.tex\relax
\endinput \ No newline at end of file
diff --git a/macros/generic/texdimens/texdimens.tex b/macros/generic/texdimens/texdimens.tex
index 189caca95d..8103bef1cd 100644
--- a/macros/generic/texdimens/texdimens.tex
+++ b/macros/generic/texdimens/texdimens.tex
@@ -1,29 +1,70 @@
% This is file texdimens.tex, part of texdimens package, which
% is distributed under the LPPL 1.3c. Copyright (c) 2021 Jean-François Burnol
-% 2021/07/15 v0.9delta
+% 2021/07/21 v0.9
+% All macros from 0.9delta release have changed names: \texdimen prefix
+% has replaced \texdimin.
\edef\texdimensendinput{\endlinechar\the\endlinechar\catcode`\noexpand _=\the\catcode`\_\relax\noexpand\endinput}%
\endlinechar13\relax%
\catcode`\_=11
%
-% Mathematics
+% Mathematics ("down" and "up" macros)
% ===========
%
-% Is T sp attainable from unit "uu"?. Here we suppose T>0.
-% phi>1, psi=1/phi, psi<1
-% U(N,phi)=trunc(N phi) is strictly increasing
+% Is T sp attainable from unit "uu"?.
+% If not, what is largest dimension < Tsp which is attainable?
+% Here we suppose T>0.
+%
+% phi>1, psi=1/phi, psi<1.
+%
+% U(N,phi)=trunc(N phi) is the strictly increasing sequence,
+% indexed by non-negative integers, of attainable dimensions.
+% (in sp unit)
+%
% U(N)<= T < U(N+1) iff N = ceil((T+1)psi) - 1
% U(M)< T <= U(M+1) iff M = ceil(T psi) - 1
-% Either:
+%
+% Stumbling block
+% ---------------
+%
+% The stumbling block is that computing "ceil((T+1)psi) - 1" without
+% overflow is not obvious: yes \numexpr/\dimexpr allow so-called
+% "scaling operations" but only in the "rounding up" variant.
+%
+% If we attempt computing the ceil(x) function via round(x+0.5),
+% for example with psi=100/7227 which corresponds to the unit "in",
+% this necessitates evaluating:
+%
+% round((((T+1)*200)+7227)/14454)
+%
+% But as far as I can tell currently, for this we need to be able
+% to evaluate without overflow (T+1)*200+7227 and this limits to
+% T's which are (roughly) such that 100 T is less than \maxdimen.
+%
+% A work-around
+% -------------
+%
+% The rest of the discussion is about an algorithm providing an
+% alternative route to N, using \numexpr/\dimexpr/TeX facilities,
+% and working with (almost, as we will see) the full range of allowed
+% T's, 0 < T <= \maxdimen. (that the algorithm works for T=0 is to be
+% checked manually after the main discussion).
+%
+% Let's return to the U(N)<= T < U(N+1) and U(M)< T <= U(M+1) equations.
+%
+% Either (recall in all of this T > 0):
+%
% case1: M = N, i.e. T is not attainable, M=N < T psi < (T+1) psi <= N+1
-% case2: M = N - 1, i.e. T is attained, T psi <= N < (T+1) psi, T = floor(N phi)
+% case2: M = N - 1, i.e. T is attained, T psi <= N < (T+1) psi, T = trunc(N phi)
%
-% Let X = round(T psi). And let Y = trunc(X phi).
+% Let X = round(T psi). And let Y = trunc(X phi). We will explain later
+% how X and Y can be computed using \numexpr/\dimexpr/TeX.
%
% case1: X can be N or N+1. It will be N+1 iff Y > T.
% case2: X can be N or N-1. It will be N iff trunc((X+1)phi)>T.
%
-% This is not convenient: if Y <= T it might still be that we are in case 2
-% and we must check then if trunc((X+1) phi) > T or not.
+% This is not convenient: if Y < T it could be that we are in case 2
+% but to decide we must check if trunc((X+1) phi) = T or not, so
+% this means a second computation.
%
% If psi < 0.5
% ------------
@@ -37,11 +78,11 @@
% a) compute X = round(T psi)
% b) compute Y = trunc(X phi) and test if Y > T. If true, we
% were in case 1, replace X by X - 1, else we were either
-% in case 1 or case 2, but we can leave X as is.
+% in case 1 or case 2, and we leave X as it is.
% We have thus found N.
%
% The operation Y = trunc(X phi) can be achieved this way:
-% i) use \the\dimexpr to convert X sp into D pt,
+% i) use \the\dimexpr to convert X sp into D pt,
% ii) use \the\numexpr\dimexpr to convert "D uu" into sp.
% These steps give Y.
%
@@ -50,14 +91,14 @@
%
% The computations of X and Y can be done independently of sign of T.
% But the final test has to be changed to Y < T if T < 0 and then
-% one must replace X by X+1. So we must filter sign.
+% one must replace X by X+1. So we must filter out the sign of the input.
%
-% If the goal is only to find a decimal D such that "D uu" is
+% If the goal is only to find a decimal D such that "D uu" is
% exactly T sp in the case this is possible, then things are simpler
% because from X = round(T psi) we get D such as X sp is same as D pt
% and "D uu" will work.
% We don't have to take sign into account for this computation.
-% But if T sp was not atteignable we don't know if this X will give
+% But if T sp was not attainable we don't know if this X will give
% a D such that D uu < T sp or D uu > T sp.
%
% If psi > 0.5
@@ -65,7 +106,7 @@
%
% For example unit "bp" has phi=803/800.
%
-% It is then not true that if T sp is atteignable, the X = round(T psi)
+% It is then not true that if T sp is attainable, the X = round(T psi)
% will always work.
%
% But it is true that R = round((T + 0.5) psi) will always work.
@@ -76,7 +117,7 @@
%
% So this gives an approach to find a D such that "D uu" is exactly
% T sp when this is possible.
-%
+%
% If Tsp (positive) is not attainable, this R however can produce
% either N or N+1.
%
@@ -86,42 +127,38 @@
% It is slightly less costly to compute X = round(T psi) than
% R = round((T + 0.5) psi),
% but if we then realize that trunc(X phi) < T we do not yet know
-% if trunc((X+1) phi) = T or is > T.
+% if trunc((X+1) phi) = T or is > T. So we proceed via R, not X,
+% to not have to make a second computation if a dimension comparison
+% test goes awry.
%
% To recapitulate: we have our algorithm for all units to find out
-% maximal dimension exactly atteignable in "uu" unit and at most equal
+% maximal dimension exactly attainable in "uu" unit and at most equal
% to (positive) T sp.
%
% Unfortunately the check that Y (in case psi < 0.5) or Z (in case psi >
-% 0.5) may trigger a Dimension too large error if T sp was near
-% non-atteignable \maxdimen.
-%
-% For additional envisioned "safe versions" we would tabulate first per unit
-% what is the integer Rmax such that trunc(Rmax phi) <= \maxdimen. Then
-% the "safe" versions would have an extra check of X or R before
-% proceeding further. But the "up macros" supposed to give the next
-% dimension above Tsp and exactly atteignable in "uu" unit, if compliant
-% to their description can not avoid "Dimension too large" for inputs
-% close to non-attainable \maxdimen.
-%
-% After having written the macros we will tabulate what is for each unit
-% the maximal attainable dimension.
-%
-% About the macros such as \texdiminbp whose constraints are:
-% - give a decimal D such that "Duu" = "T sp" for TeX if possible
-% - else give nearest from below or above without knowing
-% which one,
-%
-% there was some hesitation about whether or not using the simpler
-% round(T psi) approach for units > 2pt and the \texdimin<uu> macros.
-% Testing showed that this did not change the output for \maxdimen
-% with the units "nc" and "in": still N+1 is returned...
-%
-% As it has great
-% advantage to not have to check the sign of the input, the
-% "simpler" approach was chosen for those units to which it
-% applies, i.e. the units uu > 2pt (phi>2, psi<1/2), i.e.
-% all units except bp, nd and dd.
+% 0.5) verifies or not Y > T may trigger a Dimension too large error if
+% T sp was near non-attainable \maxdimen. It turns out this sad
+% situation happens only for the units `dd`, `nc`, and `in`, and T sp
+% very close to \maxdimen (like for all units apart from `pt`, `bp`,
+% `nd`, the \maxdimen is not attainable, and by bad luck for `dd`, `nc`,
+% and `in`, the X will correspond to a decimal D such that Duu>\maxdimen
+% is the nearest virtually attaible dimensions from above not from
+% below; see the README.md for the tabulation of the maximal usable inputs).
+%
+% Regarding the \texdimen<uu> macros, and units with phi > 2, I
+% hesitated using either the round((T+0.5)psi) or round(T psi), but for
+% Tsp = \maxdimen, both formulas turned out to give the same result for
+% all such units, so I chose for these \texdimen<uu> macros and the
+% units with phi>2 to use the simpler round(T psi) which does not need
+% to check the sign of T.
+%
+% For the "up" and "down" macros, we again use the round(T psi), but do
+% have to check the sign anyhow. We could also have used the
+% round((T+0.5)psi) which requires a sign check too, but it costs a bit
+% more. It would have allowed though to share the same codebase for all
+% units, here we have to prepare some slightly different shared macros
+% for the first batch bp, nd, dd and the second batch mm, pc, nc, cc,
+% cm, in.
%
% Implementation
% ==============
@@ -171,87 +208,164 @@
%
% pt
%
-\def\texdiminpt#1{\expandafter\texdimenstrippt\the\dimexpr#1\relax}%
+\def\texdimenpt#1{\expandafter\texdimenstrippt\the\dimexpr#1\relax}%
%
% bp 7227/7200 = 803/800
%
-\def\texdiminbp#1{\expandafter\texdiminbp_\the\numexpr\dimexpr#1;}%
-\def\texdiminbp_#1#2;{%
+\def\texdimenbp#1{\expandafter\texdimenbp_\the\numexpr\dimexpr#1;}%
+\def\texdimenbp_#1#2;{%
\expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*400/803sp\relax
}%
-% \texdiminbpdown: maximal dim exactly expressible in bp and at most equal to input
-\def\texdiminbpdown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*400/803;bp;}%
-% \texdiminbpup: minimal dim exactly expressible in bp and at least equal to input
-\def\texdiminbpup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*400/803;bp;}%
+% \texdimenbpdown: maximal dim exactly expressible in bp and at most equal to input
+\def\texdimenbpdown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*400/803;bp;}%
+% \texdimenbpup: minimal dim exactly expressible in bp and at least equal to input
+\def\texdimenbpup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*400/803;bp;}%
%
% nd 685/642
%
-\def\texdiminnd#1{\expandafter\texdiminnd_\the\numexpr\dimexpr#1;}%
-\def\texdiminnd_#1#2;{%
+\def\texdimennd#1{\expandafter\texdimennd_\the\numexpr\dimexpr#1;}%
+\def\texdimennd_#1#2;{%
\expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*321/685sp\relax
}%
-% \texdiminnddown: maximal dim exactly expressible in nd and at most equal to input
-\def\texdiminnddown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*321/685;nd;}%
-% \texdiminndup: minimal dim exactly expressible in nd and at least equal to input
-\def\texdiminndup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*321/685;nd;}%
+% \texdimennddown: maximal dim exactly expressible in nd and at most equal to input
+\def\texdimennddown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*321/685;nd;}%
+% \texdimenndup: minimal dim exactly expressible in nd and at least equal to input
+\def\texdimenndup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*321/685;nd;}%
%
% dd 1238/1157
%
-\def\texdimindd#1{\expandafter\texdimindd_\the\numexpr\dimexpr#1;}%
-\def\texdimindd_#1#2;{%
+\def\texdimendd#1{\expandafter\texdimendd_\the\numexpr\dimexpr#1;}%
+\def\texdimendd_#1#2;{%
\expandafter\texdimenstrippt\the\dimexpr\numexpr(2*#1#2+\if-#1-\fi1)*1157/2476sp\relax
}%
-% \texdimindddown: maximal dim exactly expressible in dd and at most equal to input
-\def\texdimindddown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*1157/2476;dd;}%
-% \texdiminddup: minimal dim exactly expressible in dd and at least equal to input
-\def\texdiminddup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*1157/2476;dd;}%
+% \texdimendddown: maximal dim exactly expressible in dd and at most equal to input
+\def\texdimendddown#1{\expandafter\texdimendown_A\the\numexpr\dimexpr#1;*1157/2476;dd;}%
+% \texdimenddup: minimal dim exactly expressible in dd and at least equal to input
+\def\texdimenddup#1{\expandafter\texdimenup_A\the\numexpr\dimexpr#1;*1157/2476;dd;}%
%
% mm 7227/2540 phi now >2, use from here on the simpler approach
%
-\def\texdiminmm#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*2540/7227\relax}%
-% \texdiminmmdown: maximal dim exactly expressible in mm and at most equal to input
-\def\texdiminmmdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*2540/7227;mm;}%
-% \texdiminmmup: minimal dim exactly expressible in mm and at least equal to input
-\def\texdiminmmup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*2540/7227;mm;}%
+\def\texdimenmm#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*2540/7227\relax}%
+% \texdimenmmdown: maximal dim exactly expressible in mm and at most equal to input
+\def\texdimenmmdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*2540/7227;mm;}%
+% \texdimenmmup: minimal dim exactly expressible in mm and at least equal to input
+\def\texdimenmmup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*2540/7227;mm;}%
%
% pc 12/1
%
-\def\texdiminpc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)/12\relax}%
-% \texdiminpcdown: maximal dim exactly expressible in pc and at most equal to input
-\def\texdiminpcdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;/12;pc;}%
-% \texdiminpcup: minimal dim exactly expressible in pc and at least equal to input
-\def\texdiminpcup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;/12;pc;}%
+\def\texdimenpc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)/12\relax}%
+% \texdimenpcdown: maximal dim exactly expressible in pc and at most equal to input
+\def\texdimenpcdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;/12;pc;}%
+% \texdimenpcup: minimal dim exactly expressible in pc and at least equal to input
+\def\texdimenpcup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;/12;pc;}%
%
% nc 1370/107
%
-\def\texdiminnc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*107/1370\relax}%
-% \texdiminncdown: maximal dim exactly expressible in nc and at most equal to input
-\def\texdiminncdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*107/1370;nc;}%
-% \texdiminncup: minimal dim exactly expressible in nc and at least equal to input
-\def\texdiminncup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*107/1370;nc;}%
+\def\texdimennc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*107/1370\relax}%
+% \texdimenncdown: maximal dim exactly expressible in nc and at most equal to input
+\def\texdimenncdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*107/1370;nc;}%
+% \texdimenncup: minimal dim exactly expressible in nc and at least equal to input
+\def\texdimenncup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*107/1370;nc;}%
%
% cc 14856/1157
%
-\def\texdimincc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*1157/14856\relax}%
-% \texdiminccdown: maximal dim exactly expressible in cc and at most equal to input
-\def\texdiminccdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*1157/14856;cc;}%
-% \texdiminccup: minimal dim exactly expressible in cc and at least equal to input
-\def\texdiminccup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*1157/14856;cc;}%
+\def\texdimencc#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*1157/14856\relax}%
+% \texdimenccdown: maximal dim exactly expressible in cc and at most equal to input
+\def\texdimenccdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*1157/14856;cc;}%
+% \texdimenccup: minimal dim exactly expressible in cc and at least equal to input
+\def\texdimenccup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*1157/14856;cc;}%
%
% cm 7227/254
%
-\def\texdimincm#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*254/7227\relax}%
-% \texdimincmdown: maximal dim exactly expressible in cm and at most equal to input
-\def\texdimincmdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*254/7227;cm;}%
-% \texdimincmup: minimal dim exactly expressible in cm and at least equal to input
-\def\texdimincmup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*254/7227;cm;}%
+\def\texdimencm#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*254/7227\relax}%
+% \texdimencmdown: maximal dim exactly expressible in cm and at most equal to input
+\def\texdimencmdown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*254/7227;cm;}%
+% \texdimencmup: minimal dim exactly expressible in cm and at least equal to input
+\def\texdimencmup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*254/7227;cm;}%
%
% in 7227/100
%
-\def\texdiminin#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*100/7227\relax}%
-% \texdiminindown: maximal dim exactly expressible in in and at most equal to input
-\def\texdiminindown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*100/7227;in;}%
-% \texdimininup: minimal dim exactly expressible in in and at least equal to input
-\def\texdimininup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*100/7227;in;}%
+\def\texdimenin#1{\expandafter\texdimenstrippt\the\dimexpr(#1)*100/7227\relax}%
+% \texdimenindown: maximal dim exactly expressible in in and at most equal to input
+\def\texdimenindown#1{\expandafter\texdimendown_a\the\numexpr\dimexpr#1;*100/7227;in;}%
+% \texdimeninup: minimal dim exactly expressible in in and at least equal to input
+\def\texdimeninup#1{\expandafter\texdimenup_a\the\numexpr\dimexpr#1;*100/7227;in;}%
+% both in and cm
+% Mathematics ("both" macros)
+% ===========
+%
+% Let a and b be two non-negative integers such that U = floor(a 7227/100) =
+% floor(b 7227/254). It can be proven that a=50k, b=127k for some integer k.
+% The proof is left to reader. So U = floor(7227 k /2) for some k.
+%
+% Let's now find the largest such U <= T. So U = floor(k 7227/2)<= T which is
+% equivalent (as k is integer) to k 7227/2 <= T + 1/2, i.e.
+%
+% kmax = floor((2T+1)/7227)
+%
+% If we used for x>0 the formula floor(x)=round(x-1/2)=<x-1/2> we would end
+% up basically with some 4T hence overflow problems even in \numexpr.
+% Here I used <.> to denote rounding in the sense of \numexpr. It is not
+% 1-periodical due to how negative inputs are handled, but here x-1/2>-1/2.
+%
+% The following lemma holds: let T be a non-negative integer then
+%
+% floor((2T+1)/7227) = <(2T - 3612)/7227>
+%
+% So we can compute this k, hence get a=50k, b=127k, all within \numexpr and
+% avoiding overflow.
+%
+% Implementation
+% ==============
%
+% Regarding the output in pt or sp, we seem to need floor(k 7227/2).
+% The computation of floor(k 7227/2) as <(7227 k - 1)/2> would require to
+% check if k==0 so we do it rather as <(7227 k + 1)/2> - 1. No overflow
+% can arise as k = 297147 for \maxdimen, and then 7227 k = 2**31 - 2279 and
+% there is ample room for 7227k+1 using \numexpr.
+%
+% But this step, as well as initial step to get kmax will require to separate
+% hangdling of negative input from positive one.
+%
+% Alternative
+% -----------
+%
+% For non-negative T we can compute U = ((T+1)/7227)*7227. If U <= T keep it,
+% else if U > T, replace it by U - 3614. This is alternative road to the maximal
+% floor(k 7227/2) at most equal to T.
+%
+% There is some slight under-efficiency to share macros across the 3 end targets
+% as I added one layer of parentheses.
+\def\texdimenbothincm#1{\expandafter\texdimenstrippt\the\dimexpr
+ \expandafter\texdimenboth_a\the\numexpr\dimexpr#1;127);}%
+\def\texdimenbothcmin#1{\expandafter\texdimenstrippt\the\dimexpr
+ \expandafter\texdimenboth_a\the\numexpr\dimexpr#1;50);}%
+\def\texdimenbothincmpt#1{\expandafter\texdimenstrippt\the\dimexpr
+ \expandafter\texdimenboth_a\the\numexpr\dimexpr#1;7227+1)/2-1;}%
+\let\texdimenbothcminpt\texdimenbothincmpt
+\def\texdimenboth_a#1{\if-#1\texdimenboth_neg\fi\texdimenboth_b#1}%
+% The opening parenthesis ( is closed in #2, it was added to share "pt" output
+% with the two others
+\def\texdimenboth_b#1;#2;{\numexpr(((2*#1-3612)/7227)*#2sp\relax}%
+% negative branch. This is expanded in a \dimexpr so we can insert the -
+% in front of the \numexpr.
+% #1 is \fi here and #2 is \texdimenboth_b
+\def\texdimenboth_neg#1#2-#3;#4;{#1-\numexpr(((2*#3-3612)/7227)*#4sp\relax}%
+%
+% \texdimenbothincmsp is done separately as I found no easy way to share
+% its macros with the others; alternative would have been to make it the
+% core, and derive the others from it, (\texdimencm{\texdimenbothincmsp{...}sp})
+% but then they would be less efficient than their current versions.
+% (it is a bit ironical to worry about not creating too many macros
+% in such a small package, by the way)
+\def\texdimenbothincmsp#1{\the\numexpr\expandafter\texdimenbothsp_a\the\numexpr\dimexpr#1;}%
+\def\texdimenbothsp_a#1{\if-#1\texdimenbothsp_neg\fi\texdimenbothsp_b#1}%
+\def\texdimenbothsp_b#1;{(((2*#1-3612)/7227)*7227+1)/2-1\relax}%
+% #1 is \fi
+% we need to regrab here or to add a \numexpr..\relax layer to
+% \texdimenbothsp_b (parentheses could do but using 0-(...) syntax)
+% finally doing the job of \texdimenbothsp_b directly
+\def\texdimenbothsp_neg#1#2-#3;{#1-\numexpr(((2*#3-3612)/7227)*7227+1)/2-1\relax\relax}%
+%
+\let\texdimenbothcminsp\texdimenbothincmsp
\texdimensendinput
diff --git a/macros/generic/xstring/README b/macros/generic/xstring/README
index 8234833cb9..ce2ea5d24e 100644
--- a/macros/generic/xstring/README
+++ b/macros/generic/xstring/README
@@ -1,8 +1,8 @@
_________________
xstring package
- v 1.83
- 2019/02/06
+ v 1.84
+ 2021/07/21
_________________
This package provides macros manipulating strings for programming use.
diff --git a/macros/generic/xstring/test_etex.pdf b/macros/generic/xstring/test_etex.pdf
index 4d2b8134b2..17cb0ae3ac 100644
--- a/macros/generic/xstring/test_etex.pdf
+++ b/macros/generic/xstring/test_etex.pdf
Binary files differ
diff --git a/macros/generic/xstring/test_latex.pdf b/macros/generic/xstring/test_latex.pdf
index 2642a17751..8a1ee001e8 100644
--- a/macros/generic/xstring/test_latex.pdf
+++ b/macros/generic/xstring/test_latex.pdf
Binary files differ
diff --git a/macros/generic/xstring/xstring-en.pdf b/macros/generic/xstring/xstring-en.pdf
index d7581cd5e1..7a9da7b093 100644
--- a/macros/generic/xstring/xstring-en.pdf
+++ b/macros/generic/xstring/xstring-en.pdf
Binary files differ
diff --git a/macros/generic/xstring/xstring-en.tex b/macros/generic/xstring/xstring-en.tex
index 94c46f9d3f..61b6ad8078 100644
--- a/macros/generic/xstring/xstring-en.tex
+++ b/macros/generic/xstring/xstring-en.tex
@@ -178,7 +178,7 @@ In the following chapters, all the macros will be presented this plan:
\textbf{Important}: in the following, a \argu{number} can be an integer written with numeric chars, a counter, or the result of an arithmetic operation made with the command \verbinline|\numexpr|.\smallskip
-All the macros of \Xstring are displayed in {\makeatletter\color{@xs@keywordsxstring}red}.
+All the macros of \Xstring are displayed in {\makeatletter\color{@xs@keywordsxstring}blue}.
\subsection{The tests}
\subsubsection{\ttfamily\textbackslash IfSubStr}
diff --git a/macros/generic/xstring/xstring-fr.pdf b/macros/generic/xstring/xstring-fr.pdf
index a1f72f8635..0550b0393d 100644
--- a/macros/generic/xstring/xstring-fr.pdf
+++ b/macros/generic/xstring/xstring-fr.pdf
Binary files differ
diff --git a/macros/generic/xstring/xstring-fr.tex b/macros/generic/xstring/xstring-fr.tex
index a339416149..0949306ec0 100644
--- a/macros/generic/xstring/xstring-fr.tex
+++ b/macros/generic/xstring/xstring-fr.tex
@@ -182,7 +182,7 @@ Dans ce chapitre, la totalité des macros est présentée selon ce plan :\par\no
\textbf{Important} : dans les macros qui suivent, sauf cas spécifié, un \argu{nombre} est un nombre entier, un compteur, ou le résultat d'une opération arithmétique effectuée à l'aide de la primitive \verb|\numexpr|.\smallskip
-Dans le reste du texte, les macros de \Xstring sont affichées en {\makeatletter\color{@xs@keywordsxstring}rouge}.
+Dans le reste du texte, les macros de \Xstring sont affichées en {\makeatletter\color{@xs@keywordsxstring}bleu}.
\subsection{Les tests}
\subsubsection{\ttfamily\textbackslash IfSubStr}
diff --git a/macros/generic/xstring/xstring.tex b/macros/generic/xstring/xstring.tex
index 654fe462ae..d5dcd6354f 100644
--- a/macros/generic/xstring/xstring.tex
+++ b/macros/generic/xstring/xstring.tex
@@ -1,12 +1,12 @@
-% !TeX encoding = ISO-8859-1
+% !TeX encoding = UTF-8
% Ce fichier contient le code de l'extension "xstring"
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
\def\xstringname {xstring} %
-\def\xstringversion {1.83} %
+\def\xstringversion {1.84} %
% %
-\def\xstringdate {2019/02/06} %
+\def\xstringdate {2021/07/21} %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
@@ -32,7 +32,7 @@
\immediate\write-1 {Package: xstring \xstringdate\space v\xstringversion\space String manipulations (CT)}%
\fi
\newcount\integerpart
-\newcount\decimalpart% compteurs utilisés par xstring
+\newcount\decimalpart% compteurs utilisés par xstring
\edef\restorexstringcatcode{\catcode\number`\_ =\number\catcode`\_\relax}
\catcode`\_=11
@@ -76,14 +76,14 @@
\xs_read_verb
}
-\def\setverbdelim#1{% définit quel est le délimiteur de verb
+\def\setverbdelim#1{% définit quel est le délimiteur de verb
\xs_exparg\xs_ifempty{\xs_gobarg#1}%
{}
{\errmessage{Package xstring Warning: verb delimiter "\detokenize{#1}" is not a single token}}%
- \def\xs_read_verb##1#1##2#1{\endgroup\xs_assign_verb{##2}}% on appelle l'exécution de fin
+ \def\xs_read_verb##1#1##2#1{\endgroup\xs_assign_verb{##2}}% on appelle l'exécution de fin
}
-% Assigne l'argument entre délimiteur verb dans la sc #1
+% Assigne l'argument entre délimiteur verb dans la sc #1
\def\verbtocs#1{%
\def\xs_assign_verb##1{\def#1{##1}}%
\xs_toks_toverb
@@ -99,7 +99,7 @@
\def\tokenize#1#2{%
\begingroup
- \xs_def\xs_reserved_A{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg
+ \xs_def\xs_reserved_A{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg
\everyeof\expandafter{\xs_twozeroschars#1}%
\endlinechar-1
\expandafter\xs_assigntokenizeresult\scantokens\expandafter{\expandafter\relax\xs_reserved_A}% on fait l'assignation
@@ -111,18 +111,18 @@
\def\xs_ledef{\long\edef}
\def\normalexpandarg{%
- \let\xs_def\xs_ldef% on définit \xs_call avec \def
+ \let\xs_def\xs_ldef% on définit \xs_call avec \def
\def\xs_expand##1{\unexpanded\expandafter{##1}}%
}
\let\noexpandarg\normalexpandarg% synonyme
\def\expandarg{%
- \let\xs_def\xs_ldef% on définit \xs_call avec \def
+ \let\xs_def\xs_ldef% on définit \xs_call avec \def
\def\xs_expand##1{\unexpanded\expandafter\expandafter\expandafter{##1}}%
}
\def\fullexpandarg{%
- \let\xs_def\xs_ledef% on définit\xs_call avec \edef
+ \let\xs_def\xs_ledef% on définit\xs_call avec \edef
\def\xs_expand##1{##1}% et on neutralise \xs_expand
}
@@ -144,7 +144,7 @@
\endcsname
}
-% Cette macro interne prend la 1ere unité syntaxique de #1 et assigne le résultat à #2
+% Cette macro interne prend la 1ere unité syntaxique de #1 et assigne le résultat à #2
\long\def\xs_returnfirstsyntaxunit#1#2{%
\let\xs_toks\relax
\xs_ifempty{#1}
@@ -179,18 +179,18 @@
}%
}
-% Cette macro interne est utilisée dans les macros étoilées pour :
-% 1) développer l'argument selon qu'on a choisit \fullexpandarg
-% ou \normalexpandarg, et ceci à l'aide de la macro \xs_def
-% 2) Ensuite, on détokenize ce développement de façon n'avoir plus que
+% Cette macro interne est utilisée dans les macros étoilées pour :
+% 1) développer l'argument selon qu'on a choisit \fullexpandarg
+% ou \normalexpandarg, et ceci à l'aide de la macro \xs_def
+% 2) Ensuite, on détokenize ce développement de façon n'avoir plus que
% des catcodes de 10 pour les espaces et 12 pour le reste.
\long\def\xs_expand_and_detokenize#1#2{%
\long\def#1{#2}%
- \expandafter\edef\expandafter#1\expandafter{\xs_expand#1}% on développe #2 selon le mode de développement
- \long\edef#1{\detokenize\expandafter{#1}}% puis on détokenize et on assigne à #1
+ \expandafter\edef\expandafter#1\expandafter{\xs_expand#1}% on développe #2 selon le mode de développement
+ \long\edef#1{\detokenize\expandafter{#1}}% puis on détokenize et on assigne à #1
}
-\long\def\xs_expand_and_assign#1#2{\xs_def#1{#2}}% on développe #2 selon \fullexpandarg ou \normalexpandarg
+\long\def\xs_expand_and_assign#1#2{\xs_def#1{#2}}% on développe #2 selon \fullexpandarg ou \normalexpandarg
\def\xs_arglist{0########1########2########3########4########5########6########7########8########9}
@@ -205,7 +205,7 @@
\def\xs_assign_one_arg#1{\xs_exparg\xs_assign_one_arg_i{\number\numexpr#1-1}{#1}}
\def\xs_assign_one_arg_i#1#2{\def\xs_assign_one_arg_ii##1#1##2#2##3\_nil{\def\xs_myarg{##2#2}}\expandafter\xs_assign_one_arg_ii\xs_arglist\_nil}
-% #1 : numéro du 1er argument; #2 : nombre de lignes; #3 argument optionnel; #4 : dernier numéro de l'argument devant être détokenisé si étoile
+% #1 : numéro du 1er argument; #2 : nombre de lignes; #3 argument optionnel; #4 : dernier numéro de l'argument devant être détokenisé si étoile
\def\xs_buildlines#1#2#3#4{%
\let\xs_newlines\empty
\let\xs_newargs\empty
@@ -218,7 +218,7 @@
\edef\xs_reserved_B{\ifnum##1>#4 xs_def\else xs_assign\fi}%
}% et s'il y a un argument optionnel alors, on met des crochets
{\xs_eaddtomacro\xs_newargs{\expandafter[\xs_reserved_B]}%
- \def\xs_reserved_B{xs_def}% ne pas détokéniser l'argument optionnel grace au \xs_def
+ \def\xs_reserved_B{xs_def}% ne pas détokéniser l'argument optionnel grace au \xs_def
}%
}
{\xs_eaddtomacro\xs_newargs{\expandafter{\xs_reserved_B}}%
@@ -238,7 +238,7 @@
{\let\xs_reserved_D\relax\xs_newmacro_0}%
}
-% #1 : dernier numéro de l'argument devant être détokenisé
+% #1 : dernier numéro de l'argument devant être détokenisé
% #2 : nom de la macro publique
% #3 : argument optionnel (vide si pas d'arg optionnel)
% #4 : nombre d'arguments obligatoires
@@ -263,7 +263,7 @@
\noexpand\xs_testopt{\expandafter\noexpand\csname\xs_reserved_A __\endcsname}{\ifx\xs_def\xs_ledef#3\else\unexpanded{#3}\fi}}%
\fi
}%
- % Que fait \xs_reserved_B ? Il définit :
+ % Que fait \xs_reserved_B ? Il définit :
% si #3 est vide : \NOM{\xs_ifstar{\let\xs_assign\xs_expand_and_detokenize\xs_NOM__}{\let\xs_assign\xs_expand_and_assign\xs_NOM__}}
% si #3 existe : \NOM{\xs_ifstar{\let\xs_assign\xs_expand_and_detokenize\xs_NOM_}{\let\xs_assign\xs_expand_and_assign\xs_NOM_}}
% \xs_NOM_{\xs_testopt{\xs_NOM__}{#3}}}
@@ -281,7 +281,7 @@
\ifnum#5=1 \edef\xs_reserved_D{\noexpand\noexpand\noexpand\xs_testopt{\unexpanded\expandafter{\xs_reserved_D}}{}}\fi
\xs_edefaddtomacro\xs_reserved_C{{\unexpanded\expandafter{\xs_reserved_D}}\noexpand\xs_call}%
\xs_edefaddtomacro\xs_reserved_B{{\unexpanded\expandafter{\xs_reserved_C}}}%
- % Que fait \xs_reserved_B ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif :
+ % Que fait \xs_reserved_B ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif :
% \def\xs_NOM__[##2]##3##4##5{%
% \xs_def\xs_arg_i{##2}\xs_assign\xs_arg_ii{##3}\xs_assign\xs_arg_iii{##4}\xs_asign\xs_arg_iv{##5}%
% si #5=0: \edef\xs_call{\noexpand\xs_NOM[\xs_expand\xs_arg_i]{\xs_expand\xs_arg_ii}{\xs_expand\xs_arg_iii}{\xs_expand\xs_arg_iv}}%
@@ -292,15 +292,15 @@
\def\expandafter\noexpand\csname\xs_reserved_A\endcsname
\xs_myarg\ifnum#5=1 [\unexpanded{##}\number\numexpr\ifx\empty#3\empty#4+1\else#4+2\fi]\fi
}%
- % Que fait \xs_reserved_B ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif :
+ % Que fait \xs_reserved_B ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif :
% \def \xs_NOM[##2]##3##4##5[##6]{#6}
\long\xs_reserved_B
}
-% macro générique qui lit \xs_reserved_C us par us
-% 3 sous-routines sont appelées à des moments clé :
-% \xs_atendofgroup (un groupe se finit, appel récursif)
-% \xs_atbegingroup (un groupe vient d'être ouvert)
+% macro générique qui lit \xs_reserved_C us par us
+% 3 sous-routines sont appelées à des moments clé :
+% \xs_atendofgroup (un groupe se finit, appel récursif)
+% \xs_atbegingroup (un groupe vient d'être ouvert)
% \xs_atnextsyntaxunit (la future US n'est pas un groupe)
\def\xs_read_reserved_C{%
\xs_exparg\xs_ifempty{\xs_reserved_C}%
@@ -329,9 +329,9 @@
}%
}
-% macro générique qui lit \xs_reserved_D en procédant à des tests avec \IfBeginWith
-% 1 sous-routine est appelée :
-% \xs_atoccurfound (une occurrence a été trouvée)
+% macro générique qui lit \xs_reserved_D en procédant à des tests avec \IfBeginWith
+% 1 sous-routine est appelée :
+% \xs_atoccurfound (une occurrence a été trouvée)
\def\xs_read_reserved_D{%
\xs_exparg\xs_ifempty{\xs_reserved_D}%
{\xs_ifnum{\xs_nestlevel=0 }
@@ -403,11 +403,11 @@
}%
}
-% \xs_cutafteroccur coupe l'argument #1 après la #3ème occurrence de #2
+% \xs_cutafteroccur coupe l'argument #1 après la #3ème occurrence de #2
% \xs_reserved_C : contient ce qui se trouve avant cette occurrence
% \xs_reserved_D : contient ce qui se trouve avant cette occurrence y compris cette occurrence
-% \xs_reserved_E : contient ce qui se trouve après l'occurrence
-% si l'occurrence n'existe pas ou qu'un des arguments est vide, toutes les chaines renvoyées sont vides
+% \xs_reserved_E : contient ce qui se trouve après l'occurrence
+% si l'occurrence n'existe pas ou qu'un des arguments est vide, toutes les chaines renvoyées sont vides
\long\def\xs_cutafteroccur#1#2#3{%
\xs_ifnum{#3<1 }
{\let\xs_reserved_C\empty\let\xs_reserved_E\empty\gdef\groupID{}}
@@ -425,13 +425,13 @@
\noexpand\decimalpart=\number\decimalpart\relax
}%
\expandafter\xs_exitallgroups\__temp
- \xs_gobarg% mange l'appel récursif \xs_read_reserved_D dans \xs_read_reserved_D
+ \xs_gobarg% mange l'appel récursif \xs_read_reserved_D dans \xs_read_reserved_D
}
{\xs_eaddtomacro\xs_reserved_C{\xs_reserved_E}%
}%
}%
\xs_read_reserved_D
- \xs_ifnum{\decimalpart=\numexpr(#3)\relax}% occurrence trouvée ?
+ \xs_ifnum{\decimalpart=\numexpr(#3)\relax}% occurrence trouvée ?
{\let\xs_reserved_E\xs_reserved_D
\xs_exparg{\def\xs_reserved_D}{\xs_reserved_C#2}%
}
@@ -454,16 +454,16 @@
\long\def\xs_IfBeginWith_i#1#2{%
\xs_ifempty{#2}%
- {\xs_execfirst% #2 est vide, tous les tests sont passés avec succès : on renvoie #3
+ {\xs_execfirst% #2 est vide, tous les tests sont passés avec succès : on renvoie #3
}
{\xs_ifempty{#1}%
{\xs_execsecond% #1 est vide, c'est que #2 est + long que #1 : on renvoie #4
}
{\xs_returnfirstsyntaxunit{#2}\xs_reserved_B
\xs_returnfirstsyntaxunit{#1}\xs_reserved_A
- \xs_ifx{\xs_reserved_A\xs_reserved_B}% il y a égalité...
+ \xs_ifx{\xs_reserved_A\xs_reserved_B}% il y a égalité...
{\xs_removefirstsyntaxunit{#2}\xs_reserved_B
- \xs_removefirstsyntaxunit{#1}\xs_reserved_A% on enlève les 1ere unités syntaxiques
+ \xs_removefirstsyntaxunit{#1}\xs_reserved_A% on enlève les 1ere unités syntaxiques
\xs_exptwoargs\xs_IfBeginWith_i\xs_reserved_A\xs_reserved_B
}
{\xs_execsecond
@@ -538,7 +538,7 @@
\expandafter\xs_testdot\afterinteger\_nil
\xs_ifx{\empty\afterdecimal}
{\xs_ifnum{\decimalpart=0 }
- {\xs_execfirst% partie décimale constituée de 0 --> seul cas où on renvoie vrai
+ {\xs_execfirst% partie décimale constituée de 0 --> seul cas où on renvoie vrai
}
{\expandafter\xs_defafterinteger\xs_after_intpart\relax\_nil
\xs_execsecond
@@ -583,36 +583,36 @@
\expandafter\xs_defafterdecimal\afterinteger\_nil
}
-% test d'égalité sur des chaines (et des chaines contenant des nombres)
+% test d'égalité sur des chaines (et des chaines contenant des nombres)
\long\def\xs_IfStrEqFalse_i#1#2{\let\xs_reserved_A\xs_execsecond}
-\long\def\xs_IfStrEqFalse_ii#1#2{% renvoie vrai si les 2 arg sont décimaux et s'ils sont égaux, faux sinon
+\long\def\xs_IfStrEqFalse_ii#1#2{% renvoie vrai si les 2 arg sont décimaux et s'ils sont égaux, faux sinon
\xs_IfDecimal{#1}%
{\xs_IfDecimal{#2}%
{\ifdim#1pt=#2pt
\let\xs_reserved_A\xs_execfirst
\else
\let\xs_reserved_A\xs_execsecond
- \fi% les 2 sont décimaux : on fait le test
+ \fi% les 2 sont décimaux : on fait le test
}%
- {\let\xs_reserved_A\xs_execsecond}% un seul est décimal
+ {\let\xs_reserved_A\xs_execsecond}% un seul est décimal
}%
- {\let\xs_reserved_A\xs_execsecond}% #1 n'est pas décimal
+ {\let\xs_reserved_A\xs_execsecond}% #1 n'est pas décimal
}
-\long\def\xs_TestEqual#1#2{% teste si les 2 arguments sont égaux
+\long\def\xs_TestEqual#1#2{% teste si les 2 arguments sont égaux
\def\xs_reserved_A{#1}\def\xs_reserved_B{#2}%
\xs_ifx{\xs_reserved_A\xs_reserved_B}
- {\let\xs_reserved_A\xs_execfirst}% égalité parfaite des 2 chaines
+ {\let\xs_reserved_A\xs_execfirst}% égalité parfaite des 2 chaines
{\xs_reserved_D{#1}{#2}}%
\xs_reserved_A
}
-\xs_newmacro*2\IfStrEq{}{2}{0}{% teste si les deux chaines sont égales
+\xs_newmacro*2\IfStrEq{}{2}{0}{% teste si les deux chaines sont égales
\let\xs_reserved_D\xs_IfStrEqFalse_i
\xs_TestEqual{#1}{#2}%
}
-\xs_newmacro*2\IfEq{}{2}{0}{% teste si les 2 arguments (chaine ou nombre) sont égaux
+\xs_newmacro*2\IfEq{}{2}{0}{% teste si les 2 arguments (chaine ou nombre) sont égaux
\let\xs_reserved_D\xs_IfStrEqFalse_ii
\xs_TestEqual{#1}{#2}%
}
@@ -629,12 +629,12 @@
{\xs_IfStringCase\IfEq}%
}
-\long\def\xs_IfStringCase#1#2#3{% #1=macro avec ou sans étoile #2=argument à tester #3=liste des {<cas>}{code>}
- \long\def\xs_testcase##1##2##3\_nil{% lit les 2 premieres unités syntaxiques dans ##1 et ##2. Les autres dans ##3
+\long\def\xs_IfStringCase#1#2#3{% #1=macro avec ou sans étoile #2=argument à tester #3=liste des {<cas>}{code>}
+ \long\def\xs_testcase##1##2##3\_nil{% lit les 2 premieres unités syntaxiques dans ##1 et ##2. Les autres dans ##3
#1{#2}{##1}% compare
- {\xs_testopt{\xs_IfStringCase_ii{##2}}{}}% le test est positif, on exécute le code correspondant et on mange l'argument optionnel ## BUGfix dans 1.82
+ {\xs_testopt{\xs_IfStringCase_ii{##2}}{}}% le test est positif, on exécute le code correspondant et on mange l'argument optionnel ## BUGfix dans 1.82
{\xs_ifempty{##3}%
- {\xs_testopt{\xs_IfStringCase_i}{}}% s'il n'y a plus de cas, on exécute le code <autres cas> ## BUGfix dans 1.82
+ {\xs_testopt{\xs_IfStringCase_i}{}}% s'il n'y a plus de cas, on exécute le code <autres cas> ## BUGfix dans 1.82
{\xs_testcase##3\_nil}% sinon, on recommence avec ce qui reste
}%
}%
@@ -644,19 +644,19 @@
\long\def\xs_IfStringCase_i[#1]{#1}
\long\def\xs_IfStringCase_ii#1[#2]{#1}
-% Renvoie ce qui est à gauche de l'occurence n°#1 de la sous chaine #3 dans la chaine #2
+% Renvoie ce qui est à gauche de l'occurence n°#1 de la sous chaine #3 dans la chaine #2
\xs_newmacro*3\StrBefore{1}{2}{1}{%
\xs_cutafteroccur{#2}{#3}{#1}%
\xs_exparg\xs_assign_xstringresult{\xs_reserved_C}{#4}%
}
-% Renvoie ce qui est à droite de l'occurence n°#1 de la sous chaine #3 dans la chaine #2
+% Renvoie ce qui est à droite de l'occurence n°#1 de la sous chaine #3 dans la chaine #2
\xs_newmacro*3\StrBehind{1}{2}{1}{%
\xs_cutafteroccur{#2}{#3}{#1}%
\xs_exparg\xs_assign_xstringresult{\xs_reserved_E}{#4}%
}
-% Renvoie ce qui est strictement compris entre les occurrences n°#1 et n°#2
+% Renvoie ce qui est strictement compris entre les occurrences n°#1 et n°#2
% des chaines #4 et #5 dans la chaine #3
\xs_newmacro*4\StrBetween{1,1}{3}{1}{\xs_StrBetween_i[#1]{#2}{#3}{#4}[#5]}
\long\def\xs_StrBetween_i[#1,#2]#3#4#5[#6]{%
@@ -675,7 +675,7 @@
\def\saveexploremode{\let\xs_saveexploremode\xs_exploregroups}
\def\restoreexploremode{\let\xs_exploregroups\xs_saveexploremode}
-% Remplace les #1 premières occurences de la chaine #3
+% Remplace les #1 premières occurences de la chaine #3
% par la chaine #4 dans la chaine #2
\xs_newmacro\StrSubstitute{0}{3}{1}{%
\def\xs_reserved_D{#2}\let\xs_reserved_C\empty\def\xs_reserved_E{#3}%
@@ -697,12 +697,12 @@
}%
}
-% Supprime les #1 premières occurrences de #3 dans #2
+% Supprime les #1 premières occurrences de #3 dans #2
\xs_newmacro\StrDel{0}{2}{1}{\xs_StrSubstitute[#1]{#2}{#3}{}[#4]}
\def\xs_exitallgroups{\ifnum\xs_nestlevel>0 \endgroup\expandafter\xs_exitallgroups\fi}
-% Compte combien d'unités syntaxiques contient la chaine #1 ?
+% Compte combien d'unités syntaxiques contient la chaine #1 ?
\xs_newmacro\StrLen{}{1}{1}{%
\def\xs_reserved_C{#1}\decimalpart0 \def\xs_nestlevel{0}\gdef\groupID{0}%
\let\xs_atbegingroup\relax
@@ -712,11 +712,11 @@
\xs_exparg\xs_assign_xstringresult{\number\decimalpart}{#2}%
}
-% Macro interne fermant autant de groupes que nécessaire pour trouver une unité syntaxique derrière
+% Macro interne fermant autant de groupes que nécessaire pour trouver une unité syntaxique derrière
\def\xs_continuetonext{%
\xs_exparg\xs_ifempty{\xs_reserved_C}%
{\ifnum\xs_nestlevel>0
- \xs_endgroup_eaddtomacro\xs_reserved_B{\expandafter{\xs_reserved_B}}% on concatène
+ \xs_endgroup_eaddtomacro\xs_reserved_B{\expandafter{\xs_reserved_B}}% on concatène
\expandafter\xs_continuetonext% on recommence
\fi}
{}%
@@ -729,7 +729,7 @@
{\endgroup\xs_eearg{\gdef\groupID}{\expandafter\groupID\expandafter,\number\integerpart}}%
}
-% Cette macro coupe la chaine #1 après l'unité syntaxique n°#2
+% Cette macro coupe la chaine #1 après l'unité syntaxique n°#2
\def\StrSplit{%
\xs_ifstar
{\let\xs_reserved_E\xs_continuetonext\StrSplit_i}%
@@ -738,8 +738,8 @@
\xs_newmacro\StrSplit_i{}{2}{0}{\xs_StrSplit_ii{#2}{#1}\xs_StrSplit_iii}
-% Cette macro interne coupe la chaine #2 après l'unité syntaxique n°#1
-% Le début est assigné dans \xs_reserved_B et la fin dans \xs_reserved_C
+% Cette macro interne coupe la chaine #2 après l'unité syntaxique n°#1
+% Le début est assigné dans \xs_reserved_B et la fin dans \xs_reserved_C
\long\def\xs_StrSplit_ii#1#2{%
\let\xs_reserved_B\empty\def\xs_reserved_C{#2}\def\xs_reserved_D{#1}\gdef\groupID{}%
\ifnum#1>0
@@ -759,7 +759,7 @@
{\ifx\xs_reserved_C\empty\xs_reserved_E\fi
\edef\__temp{\def\noexpand\xs_reserved_B{\unexpanded\expandafter{\xs_reserved_B}}\def\noexpand\xs_reserved_C{\unexpanded\expandafter{\xs_reserved_C}}}%
\expandafter\xs_exitallgroups\__temp
- \xs_gobarg% mange l'appel récursif \xs_read_reserved_C dans \xs_read_reserved_C
+ \xs_gobarg% mange l'appel récursif \xs_read_reserved_C dans \xs_read_reserved_C
}
{}%
}%
@@ -770,8 +770,8 @@
\def\xs_StrSplit_iii#1#2{\let#1\xs_reserved_B\let#2\xs_reserved_C}
% StrCut[n]{<texte>}{<motif>}\macroA\macroB
-% \macroA reçoit ce qui se trouve avant la n ème occurrence <motif> dans <texte>
-% \macroB reçoit ce qui est après cette n ème occurrence
+% \macroA reçoit ce qui se trouve avant la n ème occurrence <motif> dans <texte>
+% \macroB reçoit ce qui est après cette n ème occurrence
\xs_newmacro*3\StrCut{1}{2}{0}{%
\xs_ifempty{#3}%
{\gdef\groupID{}\let\xs_reserved_C\empty\let\xs_reserved_E\empty
@@ -794,7 +794,7 @@
\noexpand\decimalpart=\number\decimalpart\relax
}%
\expandafter\xs_exitallgroups\__temp
- \xs_gobarg% stoppe la récursivité dans \xs_read_reserved_D
+ \xs_gobarg% stoppe la récursivité dans \xs_read_reserved_D
}
{\xs_eaddtomacro\xs_reserved_C{\xs_reserved_E}%
}%
@@ -807,7 +807,7 @@
\long\def\xs_StrCut_iii#1#2{\let#1\xs_reserved_C\let#2\xs_reserved_E}
% De la chaine #1, renvoie ce qui se trouve entre les positions
-% #2 et #3, unités syntaxiques aux positions compris !
+% #2 et #3, unités syntaxiques aux positions compris !
\xs_newmacro\StrMid{}{3}{1}{%
\begingroup
\noexploregroups
@@ -821,21 +821,21 @@
\gdef\groupID{}%
}
-% supprime #2 unités syntaxiques à gauche dans la chaine #1
+% supprime #2 unités syntaxiques à gauche dans la chaine #1
\xs_newmacro\StrGobbleLeft{}{2}{1}{%
\let\xs_reserved_E\relax
\xs_StrSplit_ii{#2}{#1}%
\xs_exparg\xs_assign_xstringresult{\xs_reserved_C}{#3}%
}
-% extrait de #1 la chaine à gauche de longueur #2
+% extrait de #1 la chaine à gauche de longueur #2
\xs_newmacro\StrLeft{}{2}{1}{%
\let\xs_reserved_E\relax
\xs_StrSplit_ii{#2}{#1}%
\xs_exparg\xs_assign_xstringresult{\xs_reserved_B}{#3}%
}
-% supprime #2 unités syntaxiques à droite dans la chaine #1
+% supprime #2 unités syntaxiques à droite dans la chaine #1
\xs_newmacro\StrGobbleRight{}{2}{1}{%
\xs_StrLen{#1}[\xs_reserved_D]%
\let\xs_reserved_E\relax
@@ -843,7 +843,7 @@
\xs_exparg\xs_assign_xstringresult{\xs_reserved_B}{#3}%
}
-% renvoie #2 unités syntaxiques à la droite de la chaine #1
+% renvoie #2 unités syntaxiques à la droite de la chaine #1
\xs_newmacro\StrRight{}{2}{1}{%
\xs_StrLen{#1}[\xs_reserved_D]%
\let\xs_reserved_E\relax
@@ -858,10 +858,10 @@
\let\xs_atbegingroup\relax
\def\xs_atendofgroup{\expandafter\endgroup\expandafter\decimalpart\number\decimalpart\relax}%
\def\xs_atnextsyntaxunit{%
- \ifnum\decimalpart=\xs_reserved_D% la n ième US est atteinte ?
- \edef\__temp{\def\noexpand\xs_reserved_B{\unexpanded\expandafter{\xs_reserved_A}}}% on capture l'US en cours qui est celle cherchée
+ \ifnum\decimalpart=\xs_reserved_D% la n ième US est atteinte ?
+ \edef\__temp{\def\noexpand\xs_reserved_B{\unexpanded\expandafter{\xs_reserved_A}}}% on capture l'US en cours qui est celle cherchée
\expandafter\xs_exitallgroups\__temp
- \expandafter\xs_gobarg% stoppe la récursivité dans \xs_read_reserved_C
+ \expandafter\xs_gobarg% stoppe la récursivité dans \xs_read_reserved_C
\fi
}%
\xs_read_reserved_C
@@ -905,8 +905,8 @@
\def\restorecomparemode{\let\xs_comparecoeff\xs_saved_comparecoeff}
% Compare les deux arguments #1 et #2
-% Renvoie 0 s'ils sont égaux et renvoie la
-% position de la premiere unité syntaxiques différente sinon
+% Renvoie 0 s'ils sont égaux et renvoie la
+% position de la premiere unité syntaxiques différente sinon
\xs_newmacro*2\StrCompare{}{2}{1}{%
\def\xs_reserved_A{#1}%
\def\xs_reserved_B{#2}%
@@ -931,13 +931,13 @@
\xs_exparg\xs_returnfirstsyntaxunit{\xs_reserved_D}\xs_reserved_B
\xs_ifx{\xs_reserved_B\xs_reserved_A}
{\xs_exparg\xs_ifempty{\xs_reserved_A}%
- {\xs_StrCompare_iii{##1}% les 2 unités syntaxiques sont égales, on renvoie la position
+ {\xs_StrCompare_iii{##1}% les 2 unités syntaxiques sont égales, on renvoie la position
}
- {\def\xs_next{\xs_exparg\xs_StrCompare_ii{\number\numexpr##1+1}}% les 2 unités syntaxiques sont égales et non vides, on recommence
+ {\def\xs_next{\xs_exparg\xs_StrCompare_ii{\number\numexpr##1+1}}% les 2 unités syntaxiques sont égales et non vides, on recommence
\xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_C}\xs_reserved_C
\xs_exparg\xs_removefirstsyntaxunit{\xs_reserved_D}\xs_reserved_D
}%
- }% les 2 unités syntaxiques sont différentes : on renvoie la position
+ }% les 2 unités syntaxiques sont différentes : on renvoie la position
{\xs_StrCompare_iii{##1}%
}%
\xs_next
@@ -959,10 +959,10 @@
{\xs_assign_xstringresult{}{#3}% s'il ne reste plus rien, on renvoie vide
}
{\xs_exparg\xs_returnfirstsyntaxunit{\xs_reserved_C}\xs_reserved_D
- \xs_ifx{\bgroup\xs_toks}% si la 1ère unité syntaxique est un groupe explicite
+ \xs_ifx{\bgroup\xs_toks}% si la 1ère unité syntaxique est un groupe explicite
{\advance\decimalpart1 % on augmente le compteur
- \xs_ifnum{\decimalpart=\xs_reserved_A\relax}% on est au groupe cherché lors de la profondeur courante ?
- {\xs_ifx{\empty\xs_reserved_B}% on est à la profondeur maximale ?
+ \xs_ifnum{\decimalpart=\xs_reserved_A\relax}% on est au groupe cherché lors de la profondeur courante ?
+ {\xs_ifx{\empty\xs_reserved_B}% on est à la profondeur maximale ?
{\xs_exparg\xs_assign_xstringresult{\xs_reserved_D}{#3}}% on renvoie ce groupe
{\xs_exparg{\expandafter\xs_StrFindGroup_i\xs_reserved_D}{\xs_reserved_B}[#3]}% on recommence avec ce groupe et les profondeurs de recherche restantes
}
@@ -1003,7 +1003,7 @@
\def\xs_atbegingroup{\let\xs_reserved_B\empty}%
\def\xs_atnextsyntaxunit{\xs_eeaddtomacro\xs_reserved_B{\xs_reserved_A}}%
\def\xs_reserved_C{#2}%
- \xs_StrExpand_i{#1}% Appel de la macro récursive
+ \xs_StrExpand_i{#1}% Appel de la macro récursive
}
{\def\xs_reserved_B{#2}%
}
@@ -1043,185 +1043,188 @@
H I S T O R I Q U E
------------------------------------------------------------------------------
-v1.0 4/7/2008 : - Package achevé.
- 7/7/2008 : - Package publié sur CTAN.
+v1.0 4/7/2008 : - Package achevé.
+ 7/7/2008 : - Package publié sur CTAN.
------------------------------------------------------------------------------
v1.1 15/8/2008
- - Le package ne nécessite plus LaTeX et est désormais utilisable sous
+ - Le package ne nécessite plus LaTeX et est désormais utilisable sous
Plain eTeX.
- Ajout des macros \IfInteger et \IfDecimal.
- Pour cette dernière, la partie entière et la partie décimale sont
- récupérables dans les compteurs \integerpart et \decimalpart. Ce
- qu'il reste après qu'un caractère non attendu soit rencontré est
+ Pour cette dernière, la partie entière et la partie décimale sont
+ récupérables dans les compteurs \integerpart et \decimalpart. Ce
+ qu'il reste après qu'un caractère non attendu soit rencontré est
dispo dans \xs_remainafterdecimal
- Correction d'un bug dans \tokenize :
- suppression de l'expansion avec \normalexpandarg pour éviter le bug
- avec les lettres accentuées dans l'exemple : \tokenize\aa{éù}
- - Amélioration du code de la plupart des macros.
- - écriture d'une routine \xs_newmacro définissant les macros.
- - Suppression de tous les compteurs grace à \numexpr.
- - Nouvelles fonctionnalités internes dans :
+ suppression de l'expansion avec \normalexpandarg pour éviter le bug
+ avec les lettres accentuées dans l'exemple : \tokenize\aa{éù}
+ - Amélioration du code de la plupart des macros.
+ - écriture d'une routine \xs_newmacro définissant les macros.
+ - Suppression de tous les compteurs grace à \numexpr.
+ - Nouvelles fonctionnalités internes dans :
\IfSubStr
- ajout des chaines se trouvant avant et après l'occurrence testée
+ ajout des chaines se trouvant avant et après l'occurrence testée
dans les sc \xs_behind_IfSubStr et \xs_before_IfSubStr
\StrCount
- a) ajout de ce qui se trouve après la dernière occurrence dans la
+ a) ajout de ce qui se trouve après la dernière occurrence dans la
sc \xs_StrCount_afterlastocccur
- b) la macro ne dépend plus d'aucune autre
+ b) la macro ne dépend plus d'aucune autre
------------------------------------------------------------------------------
v1.2 23/8/2008
- - Amélioration du code de \StrMid \StrGobbleLeft, \StrLeft,
- \StrGobbleRight et \StrRight à l'aide de la nouvelle macro
+ - Amélioration du code de \StrMid \StrGobbleLeft, \StrLeft,
+ \StrGobbleRight et \StrRight à l'aide de la nouvelle macro
\xs_StrSplit_i
- Nouveau test \IfStrEq qui compare 2 chaines
- Nouveau test \IfEq qui compare 2 chaines (ou 2 nombres si les 2 chaines
contiennent un nombre)
- Correction d'un bug dans \xs_formatnumber. La macro n'envisageait pas le
- cas où son argument était vide ce qui faiasait planter
+ cas où son argument était vide ce qui faiasait planter
\IfDecimal{}{V}{F} et \IfInteger{}{V}{F}
------------------------------------------------------------------------------
v1.3 21/9/2008
- - Amélioration du code, mise en place de récursivités terminales dans
- toutes les macros récursives, simplification de \xs_TestEqual en
+ - Amélioration du code, mise en place de récursivités terminales dans
+ toutes les macros récursives, simplification de \xs_TestEqual en
utilisant \ifx
- Nouvelles macros \IfStrEqCase et \IfEqCase
- Teste si une chaîne est égale à plusieurs chaines données et
- exécute un code spécifique
- - Création de la macro publique \StrSplit
- Coupe la chaine en 2 à une position donnée
+ Teste si une chaîne est égale à plusieurs chaines données et
+ exécute un code spécifique
+ - Création de la macro publique \StrSplit
+ Coupe la chaine en 2 à une position donnée
- Nouvelle macro \StrCompare
- Compare 2 chaînes et renvoie la position du 1er caractère différent.
- Renvoie 0 si elles sont égales.
+ Compare 2 chaînes et renvoie la position du 1er caractère différent.
+ Renvoie 0 si elles sont égales.
------------------------------------------------------------------------------
v1.3a 29/9/2008
- Correction d'un bug : \expandafter#1
dans les macros \IfSubStrBefore et \StrBetween qui buggue si #1 est un
nombre > 9 !
- - Ré écriture de \xs_returnfirstsyntaxunit et \xs_gobarg qui
- deviennent purement développables.
- - Ré écriture de \StrLen
+ - Ré écriture de \xs_returnfirstsyntaxunit et \xs_gobarg qui
+ deviennent purement développables.
+ - Ré écriture de \StrLen
- Nouvelle macro interne \xs_cutafteroccur
- Coupe la chaine après la nième occurrence d'une sous chaine.
- - Code amélioré de \StrMid, \StrLeft, \StrGobbleLeft, \StrRight,
- \StrGobbleRight grace à \xs_cutafteroccur
+ Coupe la chaine après la nième occurrence d'une sous chaine.
+ - Code amélioré de \StrMid, \StrLeft, \StrGobbleLeft, \StrRight,
+ \StrGobbleRight grace à \xs_cutafteroccur
------------------------------------------------------------------------------
v1.4 4/11/2008
- - xstring traite ses arguments par unité syntaxique, et donc toutes les
- macros internes ont été ré-écrites à cette fin.
- - Le manuel a été ré-écrit, rendu plus clair et mieux structuré.
- - Nouvelle fonctionnalité : \expandarg
- le 1er lexème de chaque argument est 1-développé avant que la
- macro ne soit appelée. Si un argument comporte plus qu'1 lexème,
- il faut passer par \scancs*[1] pour 1-développer toutes les unités
+ - xstring traite ses arguments par unité syntaxique, et donc toutes les
+ macros internes ont été ré-écrites à cette fin.
+ - Le manuel a été ré-écrit, rendu plus clair et mieux structuré.
+ - Nouvelle fonctionnalité : \expandarg
+ le 1er lexème de chaque argument est 1-développé avant que la
+ macro ne soit appelée. Si un argument comporte plus qu'1 lexème,
+ il faut passer par \scancs*[1] pour 1-développer toutes les unités
syntaxiques.
- Correction de 2 erreurs dans le manuel anglais : 0 est la valeur par
- défaut dans \StrSubstitute et \StrDel
- - Cohérence dans les nom des séquences de contrôles temporaires qui
- sont désormais : \xs_reserved_A à \xs_reserved_E
+ défaut dans \StrSubstitute et \StrDel
+ - Cohérence dans les nom des séquences de contrôles temporaires qui
+ sont désormais : \xs_reserved_A à \xs_reserved_E
------------------------------------------------------------------------------
v1.4a 12/11/2008
- - Correction d'un bug dans \xs_StrSplit dans le cas où l'argument
- numérique est <1 : la 1ere coupure doit être vide et le seconde doit
- être égale à l'argument.
+ - Correction d'un bug dans \xs_StrSplit dans le cas où l'argument
+ numérique est <1 : la 1ere coupure doit être vide et le seconde doit
+ être égale à l'argument.
------------------------------------------------------------------------------
v1.4b 16/11/2008
- Correction de 2 bugs dans \xs_returnfirstsyntaxunit
------------------------------------------------------------------------------
v1.5 31/12/2008
- - Nouvelles fonctionnalités dans la recherche de groupes par un
- identificateur caractérisant leur imbrication. Implémentation de :
+ - Nouvelles fonctionnalités dans la recherche de groupes par un
+ identificateur caractérisant leur imbrication. Implémentation de :
1) \StrFindGroup
2) \groupID
- - Ajout des nouvelles macros génériques \xs_read_reserved_C et
+ - Ajout des nouvelles macros génériques \xs_read_reserved_C et
\xs_read_reserved_D
- Correction d'un bug dans \StrSplit : \StrSplit{{a}bc}{1}[\truc] faisait
- que \truc contenait «a{a}».
- - Correction d'un bug dans \xs_newmacro : l'argument optionnel était
- détokénisé à tort dans les macros étoilées.
- - Dans \xs_newmacro, on doit choisir le numéro du dernier argument devant
- être détokénisé dans le cas d'une macro étoilée (sachant que
+ que \truc contenait «a{a}».
+ - Correction d'un bug dans \xs_newmacro : l'argument optionnel était
+ détokénisé à tort dans les macros étoilées.
+ - Dans \xs_newmacro, on doit choisir le numéro du dernier argument devant
+ être détokénisé dans le cas d'une macro étoilée (sachant que
l'argument optionnel ne l'est jamais)
------------------------------------------------------------------------------
v1.5a 09/2/2009
- Nouvelle macro \StrExpand, sensible au mode d'exploration. La macro est
- indépendante du mode d'exploration et dispose de ses propres commandes
+ indépendante du mode d'exploration et dispose de ses propres commandes
d'exploration : \expandingroups et \noexpandingroups
- - Ré-écriture de \scancs, qui devient triviale puisque dépendant de
- \StrExpand. Il n'y a plus de version étoilée et désormais, \scancs
+ - Ré-écriture de \scancs, qui devient triviale puisque dépendant de
+ \StrExpand. Il n'y a plus de version étoilée et désormais, \scancs
est sensible au mode d'exploration.
- Correction d'un bug dans \IfInteger : \IfInteger{2.0}{V}{F} affichait F
- Correction de bugs : mettre \let\xs_reserved_E\relax avant d'appeler
\xs_StrSplit_i
- Suppression des messages d'erreur, de warning et d'info. xstring devient
donc silencieux ;)
- - Passage de 3 à 2 compteurs
- - Le manuel est désormais plus coloré, en espérant qu'il sera un peu
- plus agréable à lire !
+ - Passage de 3 à 2 compteurs
+ - Le manuel est désormais plus coloré, en espérant qu'il sera un peu
+ plus agréable à lire !
------------------------------------------------------------------------------
v1.5b 13/3/2009
- Modification d'un grand nombre de macros de telle sorte que vraiment
- n'importe quel code peut désormais être placé dans les arguments des
- macros (comme par exemple des \if, \ifx ou autre, même sans leur \fi, ce
- qui n'était pas possible jusqu'alors)
+ n'importe quel code peut désormais être placé dans les arguments des
+ macros (comme par exemple des \if, \ifx ou autre, même sans leur \fi, ce
+ qui n'était pas possible jusqu'alors)
------------------------------------------------------------------------------
v1.5c 05/6/2009
- Correction d'un bug dans \IfBeginWith : il faut appeler
\xs_returnfirstsyntaxunit pour l'argument #2 puis pour l'argument #1 et
- non pas l'inverse pour que \xs_toks reflète ce qui se trouve dans #1
- - Correction d'un bug dans \xs_returnfirstsyntaxunit au cas où #1 commence
- par un espace : mettre \xs_toks à 0
+ non pas l'inverse pour que \xs_toks reflète ce qui se trouve dans #1
+ - Correction d'un bug dans \xs_returnfirstsyntaxunit au cas où #1 commence
+ par un espace : mettre \xs_toks à 0
- Correction d'un bug dans \xs_returnfirstsyntaxunit :
\xs_returnfirstsyntaxunit{{}}\truc
- faisait que \truc se développait en un espace.
- - Correction d'un bug dans \xs_removefirstsyntaxunit où le cas
+ faisait que \truc se développait en un espace.
+ - Correction d'un bug dans \xs_removefirstsyntaxunit où le cas
\xs_removefirstsyntaxunit{ {b}}\truc
- donnait \truc se développant en «b» au lieu de «{b}».
+ donnait \truc se développant en «b» au lieu de «{b}».
------------------------------------------------------------------------------
v1.5d 28/3/2010
- Correction d'un bug dans \IfInteger : \afterinteger ne donnait pas le
- bon résultat. Par exemple avec 1.23 il renvoyait {} au lieu de {.23}
- - \xs_formatnumber ne detokenize plus ses arguments (que m'est-il passé
- par la tête pour que je code un truc comme ca ?), et donc
+ bon résultat. Par exemple avec 1.23 il renvoyait {} au lieu de {.23}
+ - \xs_formatnumber ne detokenize plus ses arguments (que m'est-il passé
+ par la tête pour que je code un truc comme ca ?), et donc
\afterinteger et \xs_afterdecimal ont des tokens ayant le bon
catcode
------------------------------------------------------------------------------
v1.6 24/10/2012
- - Correction d'un bug dans \xs_cutafteroccur au cas où #3<1
+ - Correction d'un bug dans \xs_cutafteroccur au cas où #3<1
- \IfDecimal ne \detokenize plus l'argument.
- Nouvelle version de \tokenize qui enlevait les accolades si son argument
- était entre accolades
+ était entre accolades
- Nouvelle macro \StrCut
- - \xs_cutafteroccur_i ne produit plus d'espace indésirable si #3 était
- évalué par \numexpr
+ - \xs_cutafteroccur_i ne produit plus d'espace indésirable si #3 était
+ évalué par \numexpr
------------------------------------------------------------------------------
v1.7 13/1/2013
- Correction d'un manque de rigueur dans les assignations concernant
- \groupID : elles sont toutes globales désormais
+ \groupID : elles sont toutes globales désormais
- Les macros de xstring sont \long
------------------------------------------------------------------------------
v1.7a 28/2/2013
- Correction d'un espace parasite dans \xs_removefirstsyntaxunit
------------------------------------------------------------------------------
v1.7b 29/7/2013
- - La date contenue dans \xstringdate est désormais conforme
+ - La date contenue dans \xstringdate est désormais conforme
------------------------------------------------------------------------------
v1.7c 13/10/2013
- - les macros impliquées dans \IfStrCase et \IfStrEqCase sont désormais \long
+ - les macros impliquées dans \IfStrCase et \IfStrEqCase sont désormais \long
------------------------------------------------------------------------------
v1.8 07/12/2018
- - affectations globales supprimées (sauf pour \groupID) afin de ne pas
+ - affectations globales supprimées (sauf pour \groupID) afin de ne pas
surcharger la pile de sauvegarde
- nettoyage du code, corrections de lourdeurs et maladresses
------------------------------------------------------------------------------
v1.81 09/12/2018
- - bug dans \IfInteger et \IfDecimal, la macro \xs_afterdecimal est indéfinie
- et doit être remplacée par \afterdecimal
+ - bug dans \IfInteger et \IfDecimal, la macro \xs_afterdecimal est indéfinie
+ et doit être remplacée par \afterdecimal
------------------------------------------------------------------------------
v1.82 01/02/2019
- \xs_testopt n'est pas longue et provoque un bug dans \xs_IfStrCase et
\xs_IfStrCase lorsque #1 contient \par : \xs_testopt reste courte et
- \xs_IfStringCase a été modifiée pour que cela fonctionne.
+ \xs_IfStringCase a été modifiée pour que cela fonctionne.
------------------------------------------------------------------------------
v1.83 06/02/2019
- - mauvaise approche et mauvais fix dans la v1.82 : \xs_testopt devient
- longue, pas le choix (et donc aussi \xs_ifnxttok) \ No newline at end of file
+ - mauvaise approche et mauvais fix dans la v1.82 : \xs_testopt devient
+ longue, pas le choix (et donc aussi \xs_ifnxttok)
+------------------------------------------------------------------------------
+v1.84 21/07/2021
+ - encodage du fichier xstring.tex en UTF-8