diff options
Diffstat (limited to 'macros')
98 files changed, 8801 insertions, 621 deletions
diff --git a/macros/generic/tracklang/CHANGES b/macros/generic/tracklang/CHANGES index 90d299adc3..452a7d0727 100644 --- a/macros/generic/tracklang/CHANGES +++ b/macros/generic/tracklang/CHANGES @@ -1,3 +1,22 @@ +v1.4 (2019-11-30): + + * tracklang.tex: + + - Changed \TrackLangIfFileExists to also include script and + variant in file search (search order has changed slightly). + + - Added \TrackLangRedefHook + + - New commands provided to assist integration with language + packages: + + \TrackLangAddExtraRegionFile + \TrackLangAddExtraScriptFile + \TrackLangProvidePredefinedLanguage + \TrackLangProvidePredefinedDialect + + - New switch \ifTrackLangShowVerbose for debugging + v1.3.9 (2019-11-11): * tracklang.tex: diff --git a/macros/generic/tracklang/README b/macros/generic/tracklang/README index 6c9b86401c..b3e7de27b1 100644 --- a/macros/generic/tracklang/README +++ b/macros/generic/tracklang/README @@ -1,6 +1,6 @@ -Generic TeX Bundle : tracklang v1.3.9 +Generic TeX Bundle : tracklang v1.4 -Last Modified : 2019-11-11 +Last Modified : 2019-11-30 Author : Nicola Talbot diff --git a/macros/generic/tracklang/samples/animals/animals.sty b/macros/generic/tracklang/samples/animals/animals.sty index 8b14d3b4ee..6d26c98621 100644 --- a/macros/generic/tracklang/samples/animals/animals.sty +++ b/macros/generic/tracklang/samples/animals/animals.sty @@ -1,9 +1,17 @@ \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{animals}[2016/10/06 v1.2 (NLCT) Sample package to test tracklang.sty] +\ProvidesPackage{animals}[2019/11/30 v1.2.1 (NLCT) Sample package to test tracklang.sty] -\RequirePackage{tracklang}[2016/10/07] +\RequirePackage{tracklang}[2019/11/30] -\DeclareOption*{\TrackLanguageTag{\CurrentOption}} +\DeclareOption*{% + \TrackIfKnownLanguage{\CurrentOption}% + {\PackageInfo{animals}{Tracking language `\CurrentOption'}}% successful + {% failed + \PackageError{animals}% + {Unknown language specification `\CurrentOption'}% + {You need to supply either a known dialect label or a valid language tag}% + }% +} \ProcessOptions diff --git a/macros/generic/tracklang/samples/animals/sample-animals-babel.pdf b/macros/generic/tracklang/samples/animals/sample-animals-babel.pdf Binary files differindex 330ff6a026..2485ee53c7 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals-babel.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals-babel.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals-de-poly.pdf b/macros/generic/tracklang/samples/animals/sample-animals-de-poly.pdf Binary files differindex 509be5eb63..88669915f9 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals-de-poly.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals-de-poly.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals-de.pdf b/macros/generic/tracklang/samples/animals/sample-animals-de.pdf Binary files differindex d1448c319d..07962fd91a 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals-de.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals-de.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals-poly.pdf b/macros/generic/tracklang/samples/animals/sample-animals-poly.pdf Binary files differindex 1075134907..476f2f418d 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals-poly.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals-poly.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals.pdf b/macros/generic/tracklang/samples/animals/sample-animals.pdf Binary files differindex c799fb8f3a..3ec9a8145c 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals2-de.pdf b/macros/generic/tracklang/samples/animals/sample-animals2-de.pdf Binary files differindex 07c8bf0ec6..a509e00866 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals2-de.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals2-de.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals2-de2.pdf b/macros/generic/tracklang/samples/animals/sample-animals2-de2.pdf Binary files differindex 292dcd486f..c6a6e94de9 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals2-de2.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals2-de2.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals2-de3.pdf b/macros/generic/tracklang/samples/animals/sample-animals2-de3.pdf Binary files differindex 095c57d130..09f9b2eb4d 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals2-de3.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals2-de3.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals2-de4.pdf b/macros/generic/tracklang/samples/animals/sample-animals2-de4.pdf Binary files differindex 86802c70d3..271acfcba4 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals2-de4.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals2-de4.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals2-poly.pdf b/macros/generic/tracklang/samples/animals/sample-animals2-poly.pdf Binary files differindex d0faec29a6..5f1807767c 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals2-poly.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals2-poly.pdf diff --git a/macros/generic/tracklang/samples/animals/sample-animals2.pdf b/macros/generic/tracklang/samples/animals/sample-animals2.pdf Binary files differindex bd3e154a86..8ef941783a 100644 --- a/macros/generic/tracklang/samples/animals/sample-animals2.pdf +++ b/macros/generic/tracklang/samples/animals/sample-animals2.pdf diff --git a/macros/generic/tracklang/samples/regions/sample-regions.pdf b/macros/generic/tracklang/samples/regions/sample-regions.pdf Binary files differindex 693d8b75e9..78c1c87385 100644 --- a/macros/generic/tracklang/samples/regions/sample-regions.pdf +++ b/macros/generic/tracklang/samples/regions/sample-regions.pdf diff --git a/macros/generic/tracklang/samples/regions/sample-regions2-manx.pdf b/macros/generic/tracklang/samples/regions/sample-regions2-manx.pdf Binary files differindex 40eab364f8..83340a0ce7 100644 --- a/macros/generic/tracklang/samples/regions/sample-regions2-manx.pdf +++ b/macros/generic/tracklang/samples/regions/sample-regions2-manx.pdf diff --git a/macros/generic/tracklang/samples/regions/sample-regions2-map.pdf b/macros/generic/tracklang/samples/regions/sample-regions2-map.pdf Binary files differindex 033fec24ce..635f2c1f79 100644 --- a/macros/generic/tracklang/samples/regions/sample-regions2-map.pdf +++ b/macros/generic/tracklang/samples/regions/sample-regions2-map.pdf diff --git a/macros/generic/tracklang/samples/regions/sample-regions2-map2.pdf b/macros/generic/tracklang/samples/regions/sample-regions2-map2.pdf Binary files differindex 85f8f1f150..e664c00877 100644 --- a/macros/generic/tracklang/samples/regions/sample-regions2-map2.pdf +++ b/macros/generic/tracklang/samples/regions/sample-regions2-map2.pdf diff --git a/macros/generic/tracklang/samples/regions/sample-regions2-map3.pdf b/macros/generic/tracklang/samples/regions/sample-regions2-map3.pdf Binary files differindex bbd85ced7b..aac08c391d 100644 --- a/macros/generic/tracklang/samples/regions/sample-regions2-map3.pdf +++ b/macros/generic/tracklang/samples/regions/sample-regions2-map3.pdf diff --git a/macros/generic/tracklang/samples/regions/sample-regions2-nomap.pdf b/macros/generic/tracklang/samples/regions/sample-regions2-nomap.pdf Binary files differindex 46f836a3e3..df2d0bc468 100644 --- a/macros/generic/tracklang/samples/regions/sample-regions2-nomap.pdf +++ b/macros/generic/tracklang/samples/regions/sample-regions2-nomap.pdf diff --git a/macros/generic/tracklang/samples/regions/sample-regions2.pdf b/macros/generic/tracklang/samples/regions/sample-regions2.pdf Binary files differindex 6c39680885..0b26023e24 100644 --- a/macros/generic/tracklang/samples/regions/sample-regions2.pdf +++ b/macros/generic/tracklang/samples/regions/sample-regions2.pdf diff --git a/macros/generic/tracklang/samples/sample-tracklang.pdf b/macros/generic/tracklang/samples/sample-tracklang.pdf Binary files differindex a2c23d601b..aca2dd6c84 100644 --- a/macros/generic/tracklang/samples/sample-tracklang.pdf +++ b/macros/generic/tracklang/samples/sample-tracklang.pdf diff --git a/macros/generic/tracklang/samples/sample-tracklang2.pdf b/macros/generic/tracklang/samples/sample-tracklang2.pdf Binary files differindex b8bad2af52..ef391b9912 100644 --- a/macros/generic/tracklang/samples/sample-tracklang2.pdf +++ b/macros/generic/tracklang/samples/sample-tracklang2.pdf diff --git a/macros/generic/tracklang/samples/sample-tracklang3.pdf b/macros/generic/tracklang/samples/sample-tracklang3.pdf Binary files differindex 61b4f28c70..fa54737ec5 100644 --- a/macros/generic/tracklang/samples/sample-tracklang3.pdf +++ b/macros/generic/tracklang/samples/sample-tracklang3.pdf diff --git a/macros/generic/tracklang/samples/sample-tracklang4.pdf b/macros/generic/tracklang/samples/sample-tracklang4.pdf Binary files differindex d42a97d715..ec3ffb3d4d 100644 --- a/macros/generic/tracklang/samples/sample-tracklang4.pdf +++ b/macros/generic/tracklang/samples/sample-tracklang4.pdf diff --git a/macros/generic/tracklang/samples/sample-tracklang5.pdf b/macros/generic/tracklang/samples/sample-tracklang5.pdf Binary files differindex 8c05bc36f1..48c0ad786b 100644 --- a/macros/generic/tracklang/samples/sample-tracklang5.pdf +++ b/macros/generic/tracklang/samples/sample-tracklang5.pdf diff --git a/macros/generic/tracklang/samples/sample-tracklang6.pdf b/macros/generic/tracklang/samples/sample-tracklang6.pdf Binary files differindex 47c5c053fd..037e2dade1 100644 --- a/macros/generic/tracklang/samples/sample-tracklang6.pdf +++ b/macros/generic/tracklang/samples/sample-tracklang6.pdf diff --git a/macros/generic/tracklang/tracklang.dtx b/macros/generic/tracklang/tracklang.dtx index e7e28decc4..e071563fe3 100644 --- a/macros/generic/tracklang/tracklang.dtx +++ b/macros/generic/tracklang/tracklang.dtx @@ -1,16 +1,16 @@ %\iffalse % tracklang.dtx generated using makedtx version 1.2 (c) Nicola Talbot % Command line args: -% -section "chapter" -% -author "Nicola Talbot" % -doc "tracklang-manual.tex" +% -author "Nicola Talbot" % -src "tracklang.sty\Z=>tracklang.sty" % -src "tracklang.tex\Z=>tracklang.tex" % -src "tracklang-region-codes.tex\Z=>tracklang-region-codes.tex" % -src "tracklang-scripts.sty\Z=>tracklang-scripts.sty" % -src "tracklang-scripts.tex\Z=>tracklang-scripts.tex" +% -section "chapter" % tracklang -% Created on 2019/11/11 16:00 +% Created on 2019/12/1 17:41 %\fi %\iffalse %<*package> @@ -59,7 +59,7 @@ pdfauthor={Nicola L.C. Talbot}, pdftitle={tracklang: tracking language options}]{hyperref} -\CheckSum{3986} +\CheckSum{6156} \appto\MacroFont{\scriptsize} \renewcommand*{\usage}[1]{\textit{\hyperpage{#1}}} @@ -278,11 +278,11 @@ and~\ref{tab:nonisoopts}} % %\MakeShortVerb{"} % -%\title{tracklang v1.3.9: +%\title{tracklang v1.4: %tracking language options} %\author{Nicola L. C. Talbot\\\url{http://www.dickimaw-books.com/}} % -%\date{2019-11-11} +%\date{2019-11-30} %\maketitle % %\begin{abstract} @@ -326,9 +326,14 @@ and~\ref{tab:nonisoopts}} %hard-coding the various language labels used by different language %packages. % -%Related article: \qt{Localisation of \TeX\ documents: +%Related articles: \qt{Localisation of \TeX\ documents: %\styfmt{tracklang}.} TUGBoat, Volume~37 (2016), No.~3 -%(\url{http://www.tug.org/TUGboat/tb37-3/tb117talbot.pdf}). +%(\url{http://www.tug.org/TUGboat/tb37-3/tb117talbot.pdf}), +%\href{https://www.dickimaw-books.com/latex/tracklang}{Localisation +%with \texttt{tracklang.tex}}, +%and +%\href{https://www.dickimaw-books.com/faq.php?action=view&category=tracklang}{\texttt{tracklang} +%FAQ}. % %\clearpage %\tableofcontents @@ -381,10 +386,15 @@ and~\ref{tab:nonisoopts}} %which is suboptimal but at least provides some information. %(\sty{polyglossia} now provides \cs{xpg@loaded}, which %\sty{tracklang} uses to track the root languages, but the language variant -%command \cs{xpg@vloaded} only seems to be set when the language +%command \cs{xpg@loaded} only seems to be set when the language %changes, which doesn't occur until the start of the \env{document} %environment.) % +%I also can't find any way of detecting a list of languages loaded +%through \sty{babel}'s new \ics{babelprovide} command. As far as I +%can tell, the only stored list is in \cs{bbl@loaded} which only +%contains the languages loaded through package options. +% %If the \sty{ngerman} package has been loaded, \styfmt{tracklang} %effectively does %\begin{verbatim} @@ -484,11 +494,11 @@ and~\ref{tab:nonisoopts}} %operating system: %\begin{verbatim} %\input texosquery -%\input tracklang %v1.3 +%\input tracklang % v1.3 %\TrackLangFromEnv %% load packages that use tracklang for localisation %\end{verbatim} -%Or (\sty{texosquery} v1.2 currently pending) +%Or (\sty{texosquery} v1.2) %\begin{verbatim} %\input texosquery % v1.2 %\input tracklang % v1.3 @@ -497,9 +507,10 @@ and~\ref{tab:nonisoopts}} %\TrackLanguageTag{\langtag} %% load packages that use tracklang for localisation %\end{verbatim} -%Anticipate the release of \styfmt{texosquery} v1.2: +%Linux user who may or may not have \app{texosquery} setup to run in the +%shell escape: %\begin{verbatim} -%\input texosquery +%\input texosquery %\input tracklang % v1.3 % %\ifx\TeXOSQueryLangTag\undefined @@ -620,20 +631,23 @@ and~\ref{tab:nonisoopts}} % %Let's suppose you are developing a package called %\texttt{mypackage.sty} or \texttt{mypackage.tex} and you want -%to find out what languages the document author has requested. +%to find out what languages the document author has requested. (See also: +%\href{https://www.dickimaw-books.com/latex/tracklang/otherpkg.shtml}{Using +%\texttt{tracklang.tex} in Packages with Localisation Features}.) % %Generic use: %\begin{verbatim} %\input tracklang %\end{verbatim} %(Most of the commands used in this section require at least -%\styfmt{tracklang} version 1.3.) +%\styfmt{tracklang} version 1.3 but 1.4 is better if you want to +%include the script tag in the ldf files.) %Note that \texttt{tracklang.tex} has a check to determine if %it's already been loaded, so you don't need to worry about that. % %\LaTeX\ use: %\begin{verbatim} -%\RequirePackage{tracklang}[2016/10/07]% at least v1.3 +%\RequirePackage{tracklang}[2019/11/30]% at least v1.4 %\end{verbatim} %This will picked up any language options supplied in the document %class options and will also detect if \sty{babel} or @@ -648,6 +662,19 @@ and~\ref{tab:nonisoopts}} %\begin{verbatim} %\usepackage[hy-Latn-IT-arevela]{mypackage} %\end{verbatim} +%With at least version 1.4, it's better to use \ics{TrackIfKnownLanguage}: +%\begin{verbatim} +%\DeclareOption*{% +% \TrackIfKnownLanguage{\CurrentOption}% +% {\PackageInfo{mypackage}{Tracking language `\CurrentOption'}}% successful +% {% failed +% \PackageError{mypackage}% +% {Unknown language specification `\CurrentOption'}% +% {You need to supply either a known dialect label or a valid language tag}% +% }% +%} +%\end{verbatim} +% %The rest of the example package in this section uses generic code. % %If you want to fetch the locale information from the operating @@ -685,11 +712,14 @@ and~\ref{tab:nonisoopts}} %\end{verbatim} % %Each resource file has the naming scheme \meta{prefix}\texttt{-} -%\meta{tag}\texttt{.ldf}. In this example, the \meta{prefix} is -%\texttt{mypackage}. The \meta{tag} may be the language or dialect label +%\meta{localeid}\texttt{.ldf}. In this example, the \meta{prefix} is +%\texttt{mypackage}. The \meta{localeid} part may be the language or dialect label %(for example, \texttt{english} or \texttt{british}) or a combination of the ISO %language and region codes (for example, \texttt{en-GB} or -%\texttt{en} or \texttt{GB}). +%\texttt{en} or \texttt{GB}). As from version 1.4, \meta{localeid} may +%also include the script or variant. (See the definition of +%\ics{IfTrackedLanguageFileExists} on page~\pageref{pg:filesearch} +%for further details.) % %The simplest scheme is to use the root language label (not the %dialect label) for the base language settings and use the ISO @@ -708,6 +738,11 @@ and~\ref{tab:nonisoopts}} %found). For other hooks, such as \cs{date\ldots}, use %\ics{TrackLangAddToHook}\marg{code}\marg{hook type} instead. % +%With pre-v1.4 versions of \sty{tracklang}, the script isn't included +%in the file search. If it's needed then either require at least v1.4 +%or have a base ldf file that tries to load a version for the +%particular script (which can be accessed with +%\cs{CurrentTrackedScript}). %Here's an example for a language with different writing systems. %The resource file for Serbian \texttt{mypackage-serbian.ldf}: %\begin{verbatim} @@ -737,6 +772,9 @@ and~\ref{tab:nonisoopts}} %} %\end{verbatim} % +%With v1.4+ you would just need \texttt{mypackage-sr-Latn.ldf}, +%\texttt{mypackage-sr-Cyrl.ldf} for the regionless versions. +% %\section{Language Packages} %\label{sec:summary-langpkg} % @@ -747,7 +785,9 @@ and~\ref{tab:nonisoopts}} %the document author has requested. You can use the %\styfmt{tracklang} package to identify this information %by tracking the requested localisation, so that other packages -%can have a consistent way of querying it. +%can have a consistent way of querying it. (See also: +%\href{https://www.dickimaw-books.com/latex/tracklang/langpkg.shtml}{Integrating +%\texttt{tracklang.tex} into Language Packages}.) % %Generic use: %\begin{verbatim} @@ -755,7 +795,7 @@ and~\ref{tab:nonisoopts}} %\end{verbatim} %Alternative \LaTeX\ use: %\begin{verbatim} -%\RequirePackage{tracklang}[2016/10/07] % v1.3 +%\RequirePackage{tracklang}[2019/11/30] % v1.4 %\end{verbatim} %Unlike \cs{input}, \cs{RequirePackage} will allow \styfmt{tracklang} %to pick up the document class options, but using \cs{RequirePackage} @@ -795,9 +835,8 @@ and~\ref{tab:nonisoopts}} %\texttt{british}, but the above method will change that mapping %to \texttt{UKenglish}.) % -%This now means that \cs{TrackLangAddToCaptions} command used -%at the end of \sectionref{sec:summary-localepkg} above can -%find your caption hook. You don't need the map if your dialect +%This now means that \cs{TrackLangAddToHook} and \cs{TrackLangRedefHook} commands can +%find your language hooks. You don't need the map if your dialect %label is the same as \styfmt{tracklang}'s root language label %for that locale. For example: %\begin{verbatim} @@ -820,11 +859,13 @@ and~\ref{tab:nonisoopts}} %tracked with that language. For example: %\begin{verbatim} %\def\selectlanguage#1{% -% % set up hyphenation patterns etc % \SetCurrentTrackedDialect{#1}% +% % set up hyphenation patterns etc %} %\end{verbatim} -%See the example in \sectionref{sec:summary-doc}. +%See the example in \sectionref{sec:summary-doc} or the example in +%\href{https://www.dickimaw-books.com/latex/tracklang/langpkg.shtml}{Integrating +%\texttt{tracklang.tex} into Language Packages}. % %\chapter{Generic Use} %\label{sec:generic} @@ -1342,9 +1383,9 @@ and~\ref{tab:nonisoopts}} %\end{verbatim} %will add a new dialect with the label \texttt{xxYYmod} and %\begin{verbatim} -%\TrackLanguageTag{xx-YY-Latn} +%\TrackLanguageTag{xx-Latn-YY} %\end{verbatim} -%will add a new dialect with the label \texttt{xxYYLatn}. +%will add a new dialect with the label \texttt{xxLatnYY}. % %\begin{important} %If \cs{TrackLocale} or \cs{TrackLangFromEnv} find a modifier, the @@ -1412,8 +1453,8 @@ and~\ref{tab:nonisoopts}} %\begin{verbatim} %\input tracklang %\TrackLanguageTag{en-826} -%Has en-GB-Latn been tracked? -%\GetTrackedDialectFromLanguageTag{en-GB-Latn}{\thisdialect}% +%Has en-Latn-GB been tracked? +%\GetTrackedDialectFromLanguageTag{en-Latn-GB}{\thisdialect}% %\ifx\thisdialect\empty % No! %\else @@ -1834,22 +1875,22 @@ and~\ref{tab:nonisoopts}} %that each language module has a different maintainer will the %maintainers know what tag to use for their language? % -%To help with this, \styfmt{tracklang} provides: +%\label{pg:filesearch}To help with this, \styfmt{tracklang} provides: %\begin{definition} %\ics{IfTrackedLanguageFileExists}\marg{dialect}\marg{prefix}\marg{suffix}\marg{true part}\marg{false part} %\end{definition} %This attempts to find the file called -%\meta{prefix}\meta{tag}\meta{suffix} where \meta{tag} is determined -%from \meta{dialect}. If the file is found +%\meta{prefix}\meta{localeid}\meta{suffix} where \meta{localeid} is determined +%from \meta{dialect} (see below). If the file is found %\begin{definition} %\ics{CurrentTrackedTag} %\end{definition} -%is set to \meta{tag} and \meta{true part} is done, otherwise +%is set to \meta{localeid} and \meta{true part} is done, otherwise %\meta{false part} is done. If this command %is empty, then the dialect hasn't been detected. If the dialect %has been detected, but no file can be found, then %\ics{CurrentTrackedTag} is set to the final attempt at determining -%\meta{tag}. +%\meta{localeid}. % %There's a convenient shortcut command new to version 1.3: %\begin{definition}[\DescribeMacro\TrackLangRequireDialect] @@ -1908,12 +1949,11 @@ and~\ref{tab:nonisoopts}} %Otherwise it may be empty or it may expand to the %ISO~639-1 or ISO~639-2 or ISO~639-3 code. % -%As from version 1.3, the following are also available, but -%don't contribute to the tag. %\begin{definition} %\ics{CurrentTrackedDialectModifier} %\end{definition} -%The dialect's modifier or empty if not set. +%The dialect's modifier or empty if not set. (This is set but not +%used in the set of possible \meta{localeid} values.) % %\begin{definition} %\ics{CurrentTrackedDialectVariant} @@ -1939,83 +1979,110 @@ and~\ref{tab:nonisoopts}} %\begin{definition} %\ics{CurrentTrackedDialectScript} %\end{definition} -%The dialect's script. If the -%dialect doesn't have the script set, the default script -%is used instead. For example, the file \texttt{foo-serbian.ldf} -%could test for the existence of the file -%\begin{verbatim} -%foo-serbian-\CurrentTrackedDialectScript.ldf -%\end{verbatim} -%and load it if it exists. The most convenient way is to -%use \cs{TrackLangRequestResource} (described below): -%\begin{verbatim} -%\TrackLangRequestResource -% {serbian-\CurrentTrackedDialectScript} -% {}% not found, set default code here -%\end{verbatim} -%The Cyrillic settings could then be placed in -%\texttt{foo-serbian-Cyrl.ldf} and the Latin settings in -%\texttt{foo-serbian-Latn.ldf}. +%The dialect's script. If the dialect doesn't have the script set, +%the default script for the language is used instead. % -%The \meta{tag} is determined as follows: -%\begin{enumerate} +%\cs{IfTrackedLanguageFileExists} behaves as follows: +%\begin{itemize} % \item If no dialect with the given label has been % detected, the condition evaluates to \emph{false} and % \ics{CurrentTrackedTag} is empty. +% \item If a dialect with the given label has been detected, then: +% \begin{itemize} +% \item For each possible \meta{localeid} in an ordered set of tags determined by +% the dialect label (see below), the first file matching +% \meta{prefix}\meta{localeid}\meta{suffix} that's found on +% \TeX's path results in the condition evaluating to \emph{true} and +% \ics{CurrentTrackedTag} is set to the current \meta{localeid} in the +% set. The rest of the set of possible values of \meta{localeid} is skipped. +% \item If no file matching \meta{prefix}\meta{localeid}\meta{suffix} is +% found on \TeX's path, then the condition evaluates to \emph{false} +% and \ics{CurrentTrackedTag} is set to the final \meta{localeid} in the +% set (the language label). +% \end{itemize} +%\end{itemize} % -% \item If there is no language code (ISO~639-1 or 639-2 or 639-3): -% -% \begin{enumerate} -% \item If there's also no ISO~3166-1 code (\ics{CurrentTrackedRegion} -% is empty), then \meta{tag} (\ics{CurrentTrackedTag}) is set to the -% root language (\ics{CurrentTrackedLanguage}). If the file -% \meta{prefix}\meta{tag}\meta{suffix} exists, the condition will evaluate to -% \emph{true} otherwise it will evaluate to \emph{false}. -% -% \item If there is an ISO~3166-1 code, then \meta{tag} -% (\ics{CurrentTrackedTag}) will be set to \ics{CurrentTrackedRegion} -% and if the file \meta{prefix}\meta{tag}\meta{suffix} exists, -% the condition will evaluate to \emph{true} otherwise it will evaluate -% to \emph{false}. -% \end{enumerate} -% -% \item If \ics{CurrentTrackedRegion} is empty (no ISO~3166-1 -% territory code) -% then the \meta{tag} (\ics{CurrentTrackedTag}) is set to just -% \ics{CurrentTrackedIsoCode}. -% -% If the file \meta{prefix}\meta{tag}\meta{suffix} exists, the condition will -% evaluate to \emph{true}. If the file doesn't exist and -% there are additional ISO language codes available (639-2 or 639-3) -% then the test will be repeated for the next code. -% If the test still fails, then the condition evaluates to \emph{false}. -% -% \item\label{itm:lang-country} The \meta{tag} (\ics{CurrentTrackedTag}) is then set to -%\begin{verbatim} -%\CurrentTrackedIsoCode-\CurrentTrackedRegion -%\end{verbatim} -% and if the file \meta{prefix}\meta{tag}\meta{suffix} exists, -% the condition evaluates to \emph{true}. -% -% \item The \meta{tag} (\ics{CurrentTrackedTag}) is then set to -% just \ics{CurrentTrackedIsoCode}, and if the file -% \meta{prefix}\meta{tag}\meta{suffix} exists, -% the condition evaluates to \emph{true}. If the file doesn't exist -% and there are other ISO codes (639-2 or 639-3), -% then \ics{CurrentTrackedIsoCode} is set to the next available -% language code and step~\ref{itm:lang-country} is retried. -% -% \item If there is an ISO~3166-1 region code, the -% \meta{tag} (\ics{CurrentTrackedTag}) is then set to -% \ics{CurrentTrackedRegion}, -% and if the file \meta{prefix}\meta{tag}\meta{suffix} exists, -% the condition evaluates to \emph{true}. -% -% \item Finally, the \meta{tag} (\ics{CurrentTrackedTag}) is set to -% the root language label and if the file -% \meta{prefix}\meta{tag}\meta{suffix} exist the condition -% evaluates to \emph{true} otherwise it evaluates to \emph{false}. -% +%The ordered set of possible values of \meta{localeid} is determined from +%the given dialect. +%\begin{important} +%The ordering has changed in version 1.4, which now also includes the +%script and variant. This new ordering should typically make the more +%common combinations closer to the start of the search. +%\end{important} +%The possible values of \meta{localeid} are listed below in the order of priority used +%by \cs{IfTrackedLanguageFileExists}. Note that the set may contain +%repetitions (for example, if the dialect label is the same as the +%root language label). If an item contains an element that hasn't +%been set (such as the ISO~639-3 code or a sub-language \meta{sublang} or variant) then +%that item is skipped. +%\begin{enumerate} +%\item \meta{localeid} is just the value of \ics{CurrentTrackedLanguageTag}. +%\item \meta{localeid} is just the dialect label. +% +%\item \meta{localeid} is +%\meta{ISO~639-1}\texttt{-}\meta{sublang}\texttt{-}\meta{script}\texttt{-}\meta{region}. +%\item \meta{localeid} is +%\meta{ISO~639-1}\texttt{-}\meta{script}\texttt{-}\meta{region}. +%\item \meta{localeid} is +%\meta{ISO~639-1}\texttt{-}\meta{sublang}\texttt{-}\meta{region} (if there's no script or if +%the script is the default for the given language). +%\meta{ISO~639-1}\texttt{-}\meta{region} (if there's no script or if +%the script is the default for the given language). +%\item \meta{localeid} is +%\meta{ISO~639-1}\texttt{-}\meta{sublang}\texttt{-}\meta{script}. +%\item \meta{localeid} is +%\meta{ISO~639-1}\texttt{-}\meta{script}. +%\item \meta{localeid} is \meta{ISO~639-1}\texttt{-}\meta{sublang}. +%\item \meta{localeid} is just \meta{ISO~639-1}. +% +%\item \meta{localeid} is +%\meta{ISO~639-2}\texttt{-}\meta{sublang}\texttt{-}\meta{script}\texttt{-}\meta{region}. +%\item \meta{localeid} is +%\meta{ISO~639-2}\texttt{-}\meta{script}\texttt{-}\meta{region}. +%\item \meta{localeid} is +%\meta{ISO~639-2}\texttt{-}\meta{sublang}\texttt{-}\meta{region} (if there's no script or if +%the script is the default for the given language). +%\meta{ISO~639-2}\texttt{-}\meta{region} (if there's no script or if +%the script is the default for the given language). +%\item \meta{localeid} is +%\meta{ISO~639-2}\texttt{-}\meta{sublang}\texttt{-}\meta{script}. +%\item \meta{localeid} is +%\meta{ISO~639-2}\texttt{-}\meta{script}. +%\item \meta{localeid} is \meta{ISO~639-2}\texttt{-}\meta{sublang}. +%\item \meta{localeid} is just \meta{ISO~639-2}. +% +%\item \meta{localeid} is +%\meta{ISO~639-3}\texttt{-}\meta{sublang}\texttt{-}\meta{script}\texttt{-}\meta{region}. +%\item \meta{localeid} is +%\meta{ISO~639-3}\texttt{-}\meta{script}\texttt{-}\meta{region}. +%\item \meta{localeid} is +%\meta{ISO~639-3}\texttt{-}\meta{sublang}\texttt{-}\meta{region} (if there's no script or if +%the script is the default for the given language). +%\meta{ISO~639-3}\texttt{-}\meta{region} (if there's no script or if +%the script is the default for the given language). +%\item \meta{localeid} is +%\meta{ISO~639-3}\texttt{-}\meta{sublang}\texttt{-}\meta{script}. +%\item \meta{localeid} is +%\meta{ISO~639-3}\texttt{-}\meta{script}. +%\item \meta{localeid} is \meta{ISO~639-3}\texttt{-}\meta{sublang}. +%\item \meta{localeid} is just \meta{ISO~639-3}. +% +%\item \meta{localeid} is just \meta{region}. +% +%\item \meta{localeid} is +%\meta{ISO~639-1}\texttt{-}\meta{sublang}\texttt{-}\meta{variant} +%or \meta{ISO~639-1}\texttt{-}\meta{variant} if \meta{sublang} is missing. +% +%\item \meta{localeid} is +%\meta{ISO~639-2}\texttt{-}\meta{sublang}\texttt{-}\meta{variant} +%or \meta{ISO~639-2}\texttt{-}\meta{variant} if \meta{sublang} is missing. +% +%\item \meta{localeid} is +%\meta{ISO~639-3}\texttt{-}\meta{sublang}\texttt{-}\meta{variant} +%or \meta{ISO~639-3}\texttt{-}\meta{variant} if \meta{sublang} is missing. +% +%\item \meta{localeid} is just the value of \ics{CurrentTrackedLanguage} +%(the root language label). %\end{enumerate} % %For example (pre v1.3): @@ -2055,35 +2122,82 @@ and~\ref{tab:nonisoopts}} %If, for example, \ics{ThisDialect} is \texttt{british}, then the file search will %be in the order: %\begin{enumerate} -%\item \texttt{mypackage-british.ldf} -%\item \texttt{mypackage-en-GB.ldf} -%\item \texttt{mypackage-eng-GB.ldf} -%\item \texttt{mypackage-en.ldf} -%\item \texttt{mypackage-eng.ldf} -%\item \texttt{mypackage-GB.ldf} -%\item \texttt{mypackage-english.ldf} +%\item \texttt{mypackage-en-GB.ldf} (language tag) +%\item \texttt{mypackage-british.ldf} (dialect label) +% +%\item \texttt{mypackage-en-Latn-GB.ldf} (639-1 language code, script, region) +%\item \texttt{mypackage-en-GB.ldf} (639-1 language code, region) +%\item \texttt{mypackage-en-Latn.ldf} (639-1 language code, script) +%\item \texttt{mypackage-en.ldf} (639-1 language code) +% +%\item \texttt{mypackage-eng-Latn-GB.ldf} (639-2 language code, script, region) +%\item \texttt{mypackage-eng-GB.ldf} (639-2 language code, region) +%\item \texttt{mypackage-eng-Latn.ldf} (639-2 language code, script) +%\item \texttt{mypackage-eng.ldf} (639-2 language code) +% +%\item \texttt{mypackage-GB.ldf} (region) +%\item \texttt{mypackage-english.ldf} (language label) +%\end{enumerate} +% +%If, for example, \ics{ThisDialect} is \texttt{naustrian}, then the file search will +%be in the order: +%\begin{enumerate} +%\item \texttt{mypackage-de-AT-1996.ldf} (language tag) +%\item \texttt{mypackage-naustrian.ldf} (dialect label) +% +%\item \texttt{mypackage-de-Latn-AT.ldf} (639-1 language code, script, region) +%\item \texttt{mypackage-de-AT.ldf} (639-1 language code, region) +%\item \texttt{mypackage-de-Latn.ldf} (639-1 language code, script) +%\item \texttt{mypackage-de.ldf} (639-1 language code) +% +%\item \texttt{mypackage-deu-Latn-AT.ldf} (639-2 language code, script, region) +%\item \texttt{mypackage-deu-AT.ldf} (639-2 language code, region) +%\item \texttt{mypackage-deu-Latn.ldf} (639-2 language code, script) +%\item \texttt{mypackage-deu.ldf} (639-2 language code) +% +%\item \texttt{mypackage-AT.ldf} (region) +% +%\item \texttt{mypackage-de-1996.ldf} (639-1 language code, variant) +%\item \texttt{mypackage-deu-1996.ldf} (639-2 language code, variant) +% +%\item \texttt{mypackage-german.ldf} (language label) %\end{enumerate} % %If, for example, \ics{ThisDialect} is \texttt{francais}, then the file search will %be in the order: %\begin{enumerate} -%\item \texttt{mypackage-francais.ldf} -%\item \texttt{mypackage-fr.ldf} -%\item \texttt{mypackage-fra.ldf} -%\item \texttt{mypackage-french.ldf} +%\item \texttt{mypackage-fr.ldf} (language tag) +%\item \texttt{mypackage-francais.ldf} (dialect label) +%\item \texttt{mypackage-fr-Latn.ldf} (639-1 language code, script) +%\item \texttt{mypackage-fr.ldf} (639-1 language code) +%\item \texttt{mypackage-fra-Latn.ldf} (639-2 language code, script) +%\item \texttt{mypackage-fra.ldf} (639-2 language code) +%\item \texttt{mypackage-french.ldf} (language) %\end{enumerate} %This is because the predefined \texttt{francais} option has no %region assigned to it. Be careful if the dialect label is the actual %root language. For example, if \cs{ThisDialect} is \texttt{french}, %then the file search will be in the order: %\begin{enumerate} -%\item \texttt{mypackage-french.ldf} -%\item \texttt{mypackage-fr.ldf} -%\item \texttt{mypackage-fra.ldf} -%\item \texttt{mypackage-french.ldf} +%\item \texttt{mypackage-fr.ldf} (language tag) +%\item \texttt{mypackage-french.ldf} (dialect label) +%\item \texttt{mypackage-fr-Latn.ldf} (639-1 language code, script) +%\item \texttt{mypackage-fr.ldf} (639-1 language code) +%\item \texttt{mypackage-fra-Latn.ldf} (639-2 language code, script) +%\item \texttt{mypackage-fra.ldf} (639-2 language code) +%\item \texttt{mypackage-french.ldf} (language) %\end{enumerate} %Note that the last try will always fail in this case since if the -%file exists, it will be found on the first try. +%file exists, it will be found on the second try. +% +%If the dialect label is identical to the root language label then it +%means that all associated information is the default +%for that language. For example, in the above case of \texttt{french}, +%the script is \texttt{Latn} and the region is unspecified. The root +%language label can therefore be used as the fallback in the event of +%no other match but for the specific case where the dialect is +%identical to the root language then all unnecessary file name checks +%can be skipped. % %If you're only providing support for the root languages (pre v1.3): %\begin{verbatim} @@ -2128,7 +2242,7 @@ and~\ref{tab:nonisoopts}} %input through some other method. % %Within the resource file -%\meta{pkgname}\texttt{-}\meta{tag}\texttt{.ldf}, +%\meta{pkgname}\texttt{-}\meta{localeid}\texttt{.ldf}, %you can identify the file using (new to version 1.3): %\begin{definition}[\DescribeMacro\TrackLangProvidesResource] %\cs{TrackLangProvidesResource}\marg{tag}\oarg{version info} @@ -2139,10 +2253,10 @@ and~\ref{tab:nonisoopts}} %suitable for other \TeX\ formats. % %The resource file can load another resource file -%\meta{pkgname}\texttt{-}\meta{tag2}\texttt{.ldf}, +%\meta{pkgname}\texttt{-}\meta{localeid2}\texttt{.ldf}, %using (new to version 1.3): %\begin{definition}[\DescribeMacro\TrackLangRequireResource] -%\cs{TrackLangRequireResource}\marg{tag2} +%\cs{TrackLangRequireResource}\marg{localeid2} %\end{definition} %For example, the dialect file \texttt{foo-en-GB.ldf} might need to %load the root language resource file \texttt{foo-english.ldf}: @@ -2158,13 +2272,13 @@ and~\ref{tab:nonisoopts}} %\meta{code1} if it's loaded at this point or \meta{code2} if it's %already been loaded then you can use (new to version 1.3): %\begin{definition}[\DescribeMacro\TrackLangRequireResourceOrDo] -%\cs{TrackLangRequireResourceOrDo}\marg{tag2}\marg{code1}\marg{code2} +%\cs{TrackLangRequireResourceOrDo}\marg{localeid2}\marg{code1}\marg{code2} %\end{definition} % %If you want to load a resource file if it exists (without an %error if it doesn't exist), then you can use %\begin{definition}[\DescribeMacro\TrackLangRequestResource] -%\cs{TrackLangRequestResource}\marg{tag2}\marg{not found code} +%\cs{TrackLangRequestResource}\marg{localeid2}\marg{not found code} %\end{definition} %If the file doesn't exist, \meta{not found code} is done. % @@ -2235,6 +2349,16 @@ and~\ref{tab:nonisoopts}} %This is equivalent to %\cs{TrackLangAddToHook}\marg{code}\verb|{captions}|. % +%There may be some hooks, such as \cs{date}\meta{label}, that need +%redefining rather than appending to. As from v1.4, there's an +%analogous command: +%\begin{definition}[\DescribeMacro\TrackLangRedefHook] +%\cs{TrackLangRedefHook}\marg{code}\marg{type} +%\end{definition} +%which will redefined the hook to do \meta{code}. +% +%Note that no expansion is performed on \meta{code} when appending or +%redefining a hook. % %\section{Examples} %\label{sec:examples} @@ -2258,10 +2382,20 @@ and~\ref{tab:nonisoopts}} % \NeedsTeXFormat{LaTeX2e} % \ProvidesPackage{animals} % -% \RequirePackage{tracklang}[2016/10/07] %v1.3 +% \RequirePackage{tracklang}[2019/11/30] %v1.4 % % % Any undeclared options are language settings: -% \DeclareOption*{\TrackLanguageTag{\CurrentOption}} +% +% \DeclareOption*{% +% \TrackIfKnownLanguage{\CurrentOption}% +% {\PackageInfo{animals}{Tracking language `\CurrentOption'}}% successful +% {% failed +% \PackageError{animals}% +% {Unknown language specification `\CurrentOption'}% +% {You need to supply either a known dialect label or a valid language tag}% +% }% +% } +% % \ProcessOptions % % % Default definitions @@ -2496,12 +2630,12 @@ and~\ref{tab:nonisoopts}} % %Earlier, I~mentioned the search order for %\ics{IfTrackedLanguageFileExists} where if, for example, the dialect -%is \texttt{british}, the file search will be: +%is \texttt{british}, the file search (v1.4+) will be: %\begin{enumerate} %\item \texttt{mypackage-british.ldf} %\item \texttt{mypackage-en-GB.ldf} -%\item \texttt{mypackage-eng-GB.ldf} %\item \texttt{mypackage-en.ldf} +%\item \texttt{mypackage-eng-GB.ldf} %\item \texttt{mypackage-eng.ldf} %\item \texttt{mypackage-GB.ldf} %\item \texttt{mypackage-english.ldf} @@ -2511,7 +2645,7 @@ and~\ref{tab:nonisoopts}} %countries have multiple official languages, which means that the country code on its %own may not indicate the language. % -%The reason for including just the country code as the \meta{tag} in the +%The reason for including just the country code as the \meta{localeid} in the %file search is to allow for region rather than language dependent %settings. For example, suppose I~want to write a package that needs %to know whether to use imperial or metric measurements in the @@ -2524,7 +2658,7 @@ and~\ref{tab:nonisoopts}} % %\cs{TrackLangRequireDialect} has an optional argument for adjusting %the way the resource files are loaded. Suppose I have -%\texttt{regions-}\meta{tag}\texttt{.ldf} resource files, then +%\texttt{regions-}\meta{localeid}\texttt{.ldf} resource files, then %\begin{verbatim} %\TrackLangRequireDialect{regions}{\this@dialect} %\end{verbatim} @@ -2699,7 +2833,7 @@ and~\ref{tab:nonisoopts}} %\end{document} %\end{verbatim} % -%This works because the \meta{tag} search looks for the +%This works because the \meta{localeid} search looks for the %country code before the root language label. However, this will fail if %the dialect label is the same as a root language label that has an %associated territory, marked with \fnregion\ in @@ -2913,7 +3047,9 @@ and~\ref{tab:nonisoopts}} %than a package that provides multilingual support if the user has %already loaded a language package) then you can load \styfmt{tracklang} %and use the commands below to help other packages track your -%provided languages. +%provided languages. (See also: +%\href{https://www.dickimaw-books.com/latex/tracklang/langpkg.shtml}{Integrating +%\texttt{tracklang.tex} into Language Packages}.) % %The \styfmt{tracklang} package can be loaded using %\begin{verbatim} @@ -2927,7 +3063,7 @@ and~\ref{tab:nonisoopts}} %When using \LaTeX, there's a difference between the two. %The first case prevents \styfmt{tracklang} from picking up %the document class options but skips the check for known -%language packages. This check is redundant since this is +%language packages. This check is redundant since your package is %the language package, so you need to decide is whether or %not to allow the user to set up the localisation information %through the document class options. @@ -2945,12 +3081,96 @@ and~\ref{tab:nonisoopts}} % %If you just use \cs{input}, there's a test at the start of %\texttt{tracklang.tex} to determine if it's already been loaded, so -%you don't need to worry if the user has already loaded it. +%you don't need to worry if the document has already loaded it. +% +%To integrate \sty{tracklang} into your language package, you need to consider the following +%steps: +%\begin{enumerate} +%\item Does \sty{tracklang} define your supported ISO~15924 language +%scripts in the \texttt{tracklang-scripts.tex} file? +% +%If yes, then skip this step. Otherwise create a file with the +%relevant \ics{TrackLangScriptMap} command for each unknown script and identify +%this new file with \ics{TrackLangAddExtraScriptFile} (see +%\sectionref{sec:newscripts}). This usually +%won't be necessary unless you have a custom script or a child script +%(a script that's a sub-category of another script). +% +%\item Does \sty{tracklang} recognise the root language? +% +%If yes, then skip this step. +% +%If your package is setting up a language that \sty{tracklang} +%doesn't recognise then you will need to define the root language +%using \cs{TrackLangNewLanguage} (see \sectionref{sec:newlanguages}). +% +%This usually won't be the case as \sty{tracklang} should support all +%languages that have an official ISO~639-1 alpha-2 code. +% +%If you simply have a different label from \sty{tracklang} identifying the root language, +%then you can just set up your label as a dialect using +%\cs{TrackLangProvidePredefinedDialect} (see \sectionref{sec:predefinedlabels}). +% +%\item Does \sty{tracklang} define the relevant ISO~3166 region codes +%in the \texttt{tracklang-region-codes.tex} file? +% +%If yes, then skip this step. Otherwise create a file with the +%relevant \ics{TrackLangRegionMap} command for each new region and +%identify this new file with \ics{TrackLangAddExtraRegionFile} (see +%\sectionref{sec:newregions}). This usually won't be necessary as +%\sty{tracklang} should recognise all countries that have an alpha-2 +%region code, but you may require it if you need a broader region, +%such as EU. +% +%\item Do you want to define some convenient dialect labels that can +%be used with \ics{TrackPredefinedDialect}? +% +%If no, then skip this step. Otherwise you can use +%\ics{TrackLangProvidePredefinedLanguage} for root languages +%and \ics{TrackLangProvidePredefinedDialect} for dialects with +%additional information, such as a region, sub-language or script +%(see \sectionref{sec:predefinedlabels}). +% +%\item In your language initialisation code, add the \sty{tracklang} +%code to track the particular dialect (for example, use +%\cs{TrackPredefinedDialect} for recognised dialect labels or +%use the \cs{AddTracked}\ldots\ set of commands). See +%\sectionref{sec:initnewlang}. +% +%\item In your language selection code (such as \cs{selectlanguage}), add +%\cs{SetCurrentTrackedDialect}\marg{label} to allow the document +%author to easily query the current localisation settings (such as +%the region). See \sectionref{sec:selectlanguage}. +%\end{enumerate} +% +%\section{Initialising a New Language or Dialect} +%\label{sec:initnewlang} +% +%When the user requests a particular dialect through your language +%package, you can notify \styfmt{tracklang} of this choice using +%\begin{definition} +%\cs{TrackPredefinedDialect}\marg{dialect} +%\end{definition} +%provided the dialect label is recognised by \styfmt{tracklang} (all those +%listed in \refoptstables). +% +%If there's no matching dialect predefined by \styfmt{tracklang}, you +%can just use \cs{TrackLocale} or \cs{TrackLanguageTag} +%(described in \sectionref{sec:generic}) +%with the appropriate ISO codes \emph{if you're not providing caption +%hooks}. +% +%If you are providing a captions hook mechanism +%in the form \ics{captions\meta{dialect}}, then if \meta{dialect} +%doesn't match the corresponding \styfmt{tracklang} dialect label, +%you can provide a mapping using +%\cs{SetTrackedDialectLabelMap}, described below. % -%When the language is set (using commands like \cs{selectlanguage} -%) -%it would be convenient to users and other packages if the -%following command is also used: +%\section{Switching Language or Dialect} +%\label{sec:selectlanguage} +% +%When the document author switches to a different language or +%dialect, the current localisation information can be set with: %\begin{definition}[\DescribeMacro\SetCurrentTrackedDialect] %\cs{SetCurrentTrackedDialect}\marg{dialect} %\end{definition} @@ -2994,25 +3214,118 @@ and~\ref{tab:nonisoopts}} %to \meta{dialect}. See the accompanying sample file %\texttt{sample-setlang.tex} for an example.) % -%When the user requests a particular dialect through your language -%package, you can notify \styfmt{tracklang} of this choice using -%\begin{definition} -%\cs{TrackPredefinedDialect}\marg{dialect} +%\section{Defining New Scripts} +%\label{sec:newscripts} +% +%The \texttt{tracklang-scripts.tex} file isn't automatically loaded, +%but if it is then, as from v1.4, it contains a hook at the end of +%the file that can be used to load additional files that define +%supplementary scripts. This entails creating a file called, say, +%\texttt{mypackage-scripts.tex} that contains: +%\begin{definition}[\DescribeMacro\TrackLangScriptMap] +%\cs{TrackLangScriptMap}\marg{alpha code}\marg{numeric +%code}\marg{name}\marg{direction}\marg{parent} +%\end{definition} +%The first argument \meta{alpha code} is the four-letter ISO~15924 code (such as +%\texttt{Latn}), the second argument is the numeric code (such as +%215), the third argument \meta{name} is the name of the script (such +%as \texttt{Latin}), the fourth argument is the direction (such as +%\texttt{LR} for left-to-right) and the final argument is the parent +%script (leave blank if there's no parent). Note that this command will override any previous +%mapping for those codes. No check is performed to determine if they +%have already been defined. +% +%The supplementary file should be identified with: +%\begin{definition}[\DescribeMacro\TrackLangAddExtraScriptFile] +%\cs{TrackLangAddExtraScriptFile}\marg{filename} +%\end{definition} +% +%\section{Defining New Regions} +%\label{sec:newregions} +% +%The \texttt{tracklang-region-codes.tex} file isn't automatically loaded, +%but if it is then, as from v1.4, it contains a hook at the end of +%the file that can be used to load additional files that define +%supplementary regions. This entails creating a file called, say, +%\texttt{mypackage-regions.tex} that contains: +%\begin{definition}[\DescribeMacro\TrackLangRegionMap] +%\cs{TrackLangRegionMap}\marg{numeric code}\marg{alpha-2 code}\marg{alpha-3 code} +%\end{definition} +%where the first argument is the numeric region code (such as 826), +%the second argument is the alpha-2 region code (such as \texttt{GB}) +%and the third argument is the alpha-3 region code (such as +%\texttt{GBR}). Note that this command will override any previous +%mapping for those codes. No check is performed to determine if they +%have already been defined. +% +%The supplementary file should be identified with: +%\begin{definition}[\DescribeMacro\TrackLangAddExtraRegionFile] +%\cs{TrackLangAddExtraRegionFile}\marg{filename} +%\end{definition} +% +%\section{Defining a New Language} +%\label{sec:newlanguages} +% +%(New to version 1.3.) +%If the root language isn't recognised by \styfmt{tracklang} +%(not listed in \tableref{tab:rootlangopts}), then +%it can be defined (but not tracked at this point) using: +%\begin{definition}[\DescribeMacro\TrackLangNewLanguage] +%\cs{TrackLangNewLanguage}\marg{language name}\marg{639-1 +%code}\marg{639-2 (T)}\marg{639-2 (B)}\marg{639-3}\marg{3166-1}\marg{default +%script} %\end{definition} -%if the dialect label is recognised by \styfmt{tracklang} (all those -%listed in \refoptstables). +%where \meta{language name} is the root language name, +%\meta{639-1 code} is the ISO 639-1 code for that language (may be +%empty if there isn't one), \meta{639-2 (T)} is the ISO 639-2 (T) +%code for that language (may be empty if there isn't one), +%\meta{639-2 (B)} is the ISO 639-2 (B) code for that language (may be +%empty if it's the same as \meta{639-2 (T)}), \meta{639-3} is the ISO +%639-3 code for that language (empty if the same as the 639-2 +%code), \meta{3166-1} is the territory ISO code for languages that are only spoken in one +%territory (should be empty if the language is spoken in multiple +%territories), and \meta{default script} is the default script (empty +%if disputed or varies according to region). % -%If there's no matching dialect predefined by \styfmt{tracklang}, you -%can just use \cs{TrackLocale} or \cs{TrackLanguageTag} -%(described in \sectionref{sec:generic}) -%with the appropriate ISO codes \emph{if you're not providing caption -%hooks}. +%You can then track this language using \cs{AddTrackedDialect} for +%dialects or, if no regional variant is needed, you can instead use: +%\begin{definition}[\DescribeMacro\AddTrackedLanguage] +%\cs{AddTrackedLanguage}\marg{root language label} +%\end{definition} +%This is equivalent to \ics{AddTrackedDialect}\marg{root language +%label}\marg{root language label}. % -%If you are providing a captions hook mechanism -%in the form \ics{captions\meta{dialect}}, then if \meta{dialect} -%doesn't match the corresponding \styfmt{tracklang} dialect label, -%you can provide a mapping using -%\cs{SetTrackedDialectLabelMap}, described below. +% +%\section{Defining New \styfmt{tracklang} Labels} +%\label{sec:predefinedlabels} +% +%A dialect label may be predefined with associated information that +%allows that particular combination to be easily tracked with +%\cs{TrackPredefinedDialect}. In the case of a dialect label that +%only requires the information provided in \cs{TrackLangNewLanguage} +%you can use: +%\begin{definition}[\DescribeMacro\TrackLangProvidePredefinedLanguage] +%\cs{TrackLangProvidePredefinedLanguage}\marg{label} +%\end{definition} +%where \meta{label} corresponds to the language label used in +%\cs{TrackLangNewLanguage}. This allows +%\cs{TrackPredefinedDialect}\marg{label} to not only track the root +%language but also the associated ISO codes. +% +%If the dialect label doesn't match the root language label then use: +%\begin{definition}[\DescribeMacro\TrackLangProvidePredefinedDialect] +%\cs{TrackLangProvidePredefinedDialect}\marg{dialect}\marg{language}\marg{region}\marg{modifier}\marg{variant}\marg{map}\marg{script} +%\end{definition} +%where \meta{dialect} is the new \sty{tracklang} dialect label, +%\marg{language} is the \sty{tracklang} root language label, +%\meta{region} is the ISO~3166-1 region code (may be empty), +%\meta{modifier} is the modifier (may be empty), \meta{variant} +%is the variant information (may be empty), \meta{map} is your +%package's language label that corresponds to the \sty{tracklang} +%dialect label supplied in the first argument (may be empty if +%identical), and \meta{script} is the ISO~15914 alpha-4 script code +%(may be empty if it's the same as the default script for the root +%language). % %For compatibility with pre version 1.3, %if the dialect isn't predefined by @@ -3153,34 +3466,7 @@ and~\ref{tab:nonisoopts}} %where \meta{dialect} is the dialect label and \meta{value} is the %additional information. % -%(New to version 1.3.) -%If the root language isn't recognised by \styfmt{tracklang} -%(not listed in \tableref{tab:rootlangopts}), then -%it can be defined (but not tracked at this point) using: -%\begin{definition}[\DescribeMacro\TrackLangNewLanguage] -%\cs{TrackLangNewLanguage}\marg{language name}\marg{639-1 -%code}\marg{639-2 (T)}\marg{639-2 (B)}\marg{639-3}\marg{3166-1}\marg{default -%script} -%\end{definition} -%where \meta{language name} is the root language name, -%\meta{639-1 code} is the ISO 639-1 code for that language (may be -%empty if there isn't one), \meta{639-2 (T)} is the ISO 639-2 (T) -%code for that language (may be empty if there isn't one), -%\meta{639-2 (B)} is the ISO 639-2 (B) code for that language (may be -%empty if it's the same as \meta{639-2 (T)}), \meta{639-3} is the ISO -%639-3 code for that language (empty if the same as the 639-2 -%code), \meta{3166-1} is the territory ISO code for languages that are only spoken in one -%territory (should be empty if the language is spoken in multiple -%territories), and \meta{default script} is the default script (empty -%if disputed or varies according to region). -% -%You can then track this language using \cs{AddTrackedDialect} for -%dialects or, if no regional variant is needed, you can instead use: -%\begin{definition}[\DescribeMacro\AddTrackedLanguage] -%\cs{AddTrackedLanguage}\marg{root language label} -%\end{definition} -%This is equivalent to \ics{AddTrackedDialect}\marg{root language -%label}\marg{root language label}. +%\section{Example} % %Suppose I want to create a language package \texttt{alien.sty} that defines the %\texttt{martian} language with regional dialects @@ -3227,7 +3513,7 @@ and~\ref{tab:nonisoopts}} % } %\end{verbatim} %The caption commands and language set up are in the files -%\texttt{alien-}\meta{tag}\texttt{.ldf} as in the examples from +%\texttt{alien-}\meta{localeid}\texttt{.ldf} as in the examples from %\sectionref{sec:examples}. This allows for the user having already %loaded \styfmt{tracklang} before \styfmt{alien} and used \cs{TrackLangFromEnv} to pick up %the locale from the operating system's environment variables. @@ -3297,7 +3583,7 @@ and~\ref{tab:nonisoopts}} % packages such as \styfmt{etoolbox}. % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{tracklang}[2019/11/11 v1.3.9 (NLCT) Track Languages] +\ProvidesPackage{tracklang}[2019/11/30 v1.4 (NLCT) Track Languages] % \end{macrocode} %\begin{macro}{\@tracklang@declareoption} % Set up package options. @@ -3593,7 +3879,7 @@ and~\ref{tab:nonisoopts}} % Version info. % \begin{macrocode} \expandafter\def\csname ver@tracklang.tex\endcsname{% - 2019/11/11 v1.3.9 (NLCT) Track Languages Generic Code} + 2019/11/30 v1.4 (NLCT) Track Languages Generic Code} % \end{macrocode} % Define a long command for determining the existence of a control % sequence by its name. (\cs{relax} is considered undefined.) @@ -3729,6 +4015,29 @@ and~\ref{tab:nonisoopts}} % \end{macrocode} %\end{macro} % +%\begin{macro}{\@tracklang@ifcseqcsname} +%\changes{1.4}{2019-11-30}{new} +%\begin{definition} +%\cs{@tracklang@ifcseqcsname}\marg{cs}\marg{csname}\marg{true}\marg{false} +%\end{definition} +%Compares two commands, the first is reference as a control sequence +%the second is referenced as a control sequence name. Condition is +%false if the second isn't defined (no check for the existence of +%the first). +% \begin{macrocode} +\def\@tracklang@ifcseqcsname#1#2#3#4{% + \@tracklang@ifundef{#2}{#4}% + {% + \expandafter\ifx\expandafter#1\csname#2\endcsname + #3% + \else + #4% + \fi + }% +} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\@tracklang@sanitize} %\changes{1.3}{2016-10-07}{new} % \begin{macrocode} @@ -3745,15 +4054,17 @@ and~\ref{tab:nonisoopts}} % %\begin{macro}{\@tracklang@firstoftwo} %\changes{1.3}{2016-10-07}{new} +%\changes{1.4}{2019-11-30}{made long} % \begin{macrocode} -\def\@tracklang@firstoftwo#1#2{#1} +\long\def\@tracklang@firstoftwo#1#2{#1} % \end{macrocode} %\end{macro} % %\begin{macro}{\@tracklang@secondoftwo} %\changes{1.3}{2016-10-07}{new} +%\changes{1.4}{2019-11-30}{made long} % \begin{macrocode} -\def\@tracklang@secondoftwo#1#2{#2} +\long\def\@tracklang@secondoftwo#1#2{#2} % \end{macrocode} %\end{macro} % @@ -3842,6 +4153,28 @@ and~\ref{tab:nonisoopts}} % \end{macrocode} %\end{macro} % +%\begin{macro}{\ifTrackLangShowVerbose} +%\changes{1.4}{2019-11-30}{new} +% Allow user to switch verbose (debugging) information messages on or off. +% Note that verbose information will be off regardless of this +% switch if the info switch is off. +% \begin{macrocode} +\newif\ifTrackLangShowVerbose +\TrackLangShowVerbosefalse +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@verbose} +%\changes{1.4}{2019-11-30}{new} +% \begin{macrocode} +\def\@tracklang@verbose#1{% + \ifTrackLangShowVerbose + \@tracklang@info{#1}% + \fi +}% +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\@tracklang@IfFileExists} % \begin{macrocode} \ifx\IfFileExists\undefined @@ -5201,9 +5534,11 @@ and~\ref{tab:nonisoopts}} % \begin{macrocode} \def\SetCurrentTrackedDialect#1{% \edef\CurrentTrackedDialect{#1}% + \@tracklang@verbose{Setting current tracked dialect `\CurrentTrackedDialect'}% \IfTrackedDialect{\CurrentTrackedDialect}% {}% {% + \@tracklang@verbose{Not a recognised tracklang label}% % \end{macrocode} % Has a mapping from this dialect to a tracklang dialect been supplied? % \begin{macrocode} @@ -5213,6 +5548,7 @@ and~\ref{tab:nonisoopts}} {% \edef\CurrentTrackedDialect{\GetTrackedDialectFromMapping {\CurrentTrackedDialect}}% + \@tracklang@verbose{Mapping found to tracklang label `\CurrentTrackedDialect'}% }% {% % \end{macrocode} @@ -5220,32 +5556,41 @@ and~\ref{tab:nonisoopts}} % \begin{macrocode} \IfTrackedLanguage{#1}% {% + \@tracklang@verbose{Supplied label is a root language. + Finding last tracked dialect for language `#1'}% % \end{macrocode} % Get the last dialect to be tracked with this language. -% \begin{macrocode} +% \begin{macrocode} \edef\@tracklang@dialects{\TrackedDialectsFromLanguage{#1}}% \@tracklang@for\@tracklang@dialect:=\@tracklang@dialects\do{% \let\CurrentTrackedDialect\@tracklang@dialect }% }% - {}% + {% + \@tracklang@verbose{No tracklang dialect found for label `#1'}% + }% }% }% {% + \@tracklang@verbose{No mapping found}% % \end{macrocode} % Has the root language name been supplied? % \begin{macrocode} \IfTrackedLanguage{#1}% {% + \@tracklang@verbose{Supplied label is a root language. + Finding last tracked dialect for language `#1'}% % \end{macrocode} % Get the last dialect to be tracked with this language. -% \begin{macrocode} +% \begin{macrocode} \edef\@tracklang@dialects{\TrackedDialectsFromLanguage{#1}}% \@tracklang@for\@tracklang@dialect:=\@tracklang@dialects\do{% \let\CurrentTrackedDialect\@tracklang@dialect }% }% - {}% + {% + \@tracklang@verbose{No tracklang dialect found for label `#1'}% + }% }% }% \IfTrackedDialect{\CurrentTrackedDialect}% @@ -5308,6 +5653,17 @@ and~\ref{tab:nonisoopts}} }% }% }% + \@tracklang@verbose{Current tracked dialect: `\CurrentTrackedDialect'.\MessageBreak + Language: `\CurrentTrackedLanguage'.\MessageBreak + ISO code: `\CurrentTrackedIsoCode'.\MessageBreak + Sub-lang: `\CurrentTrackedDialectSubLang'.\MessageBreak + Modifier: `\CurrentTrackedDialectModifier'.\MessageBreak + Variant: `\CurrentTrackedDialectVariant'.\MessageBreak + Script: `\CurrentTrackedDialectScript'.\MessageBreak + Region: `\CurrentTrackedRegion'.\MessageBreak + Additional: `\CurrentTrackedDialectAdditional'.\MessageBreak + Tag: `\CurrentTrackedLanguageTag'. + }% }% {% \@tracklang@warn{Unknown dialect label `#1' passed to @@ -6157,6 +6513,86 @@ and~\ref{tab:nonisoopts}} % \end{macrocode} %\end{macro} % +%\begin{macro}{\@tracklang@input@extra@region@filelist} +%\changes{1.4}{2019-11-30}{new} +% \begin{macrocode} +\def\@tracklang@extra@region@filelist{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TrackLangAddExtraRegionFile} +%\changes{1.4}{2019-11-30}{new} +% Add a file name to the list of extra region code files that should +% be input by tracklang-regions-codes.tex +% \begin{macrocode} +\def\TrackLangAddExtraRegionFile#1{% + \ifx\TrackLangRegionMap\undefined + \else +% \end{macrocode} +% tracklang-region-codes.tex has already been loaded so input the file +% now. +% \begin{macrocode} + \@tracklang@input #1\relax + \fi + \@tracklang@add{#1}{\@tracklang@extra@region@filelist}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@input@extra@region@files} +%\changes{1.4}{2019-11-30}{new} +% Iterate through list of extra region files to allow other packages +% to define new regions. +% \begin{macrocode} +\def\@tracklang@input@extra@region@files{% + \@tracklang@for\@tracklang@currfile:=\@tracklang@extra@region@filelist\do + {% + \@tracklang@input\@tracklang@currfile + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@input@extra@script@filelist} +%\changes{1.4}{2019-11-30}{new} +% \begin{macrocode} +\def\@tracklang@extra@script@filelist{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TrackLangAddExtraScriptFile} +%\changes{1.4}{2019-11-30}{new} +% Add the given file name to the list of files that should be +% automatically loaded by tracklang-scripts.tex +% \begin{macrocode} +\def\TrackLangAddExtraScriptFile#1{% + \ifx\TrackLangScriptMap\undefined + \else +% \end{macrocode} +% tracklang-scripts.tex has already been loaded so input the file +% now. +% \begin{macrocode} + \@tracklang@input #1\relax + \fi + \@tracklang@add{#1}{\@tracklang@extra@script@filelist}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@input@extra@script@files} +%\changes{1.4}{2019-11-30}{new} +% Iterate through list of extra script files to allow other packages +% to define new scripts. +% \begin{macrocode} +\def\@tracklang@input@extra@script@files{% + \@tracklang@for\@tracklang@currfile:=\@tracklang@extra@script@filelist\do + {% + \@tracklang@input\@tracklang@currfile + }% +} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\GetTrackedDialectFromLanguageTag} %\changes{1.3}{2016-10-07}{new} %\begin{definition} @@ -6589,6 +7025,21 @@ and~\ref{tab:nonisoopts}} % \end{macrocode} %\end{macro} % +%\begin{macro}{\TrackLangProvidePredefinedLanguage} +%\changes{1.4}{2019-11-30}{new} +% Set up a language label for use with \cs{TrackPredefinedDialect}. +% Note that this doesn't check if already defined. +% \begin{macrocode} +\def\TrackLangProvidePredefinedLanguage#1{% + \@tracklang@namedef{@tracklang@add@#1}{% + \AddTrackedLanguage{#1}% + \AddTrackedLanguageIsoCodes{#1}% + \AddTrackedCountryIsoCode{#1}% + }% +} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\TrackLangDeclareLanguageOption} %\changes{1.3}{2016-10-07}{new} %\begin{definition} @@ -6605,11 +7056,7 @@ and~\ref{tab:nonisoopts}} \@tracklang@ifundef{@tracklang@add@#1}% {% \TrackLangNewLanguage{#1}{#2}{#3}{#4}{#5}{#6}{#7}% - \@tracklang@namedef{@tracklang@add@#1}{% - \AddTrackedLanguage{#1}% - \AddTrackedLanguageIsoCodes{#1}% - \AddTrackedCountryIsoCode{#1}% - }% + \TrackLangProvidePredefinedLanguage{#1}% \@tracklang@declareoption{#1}% }% {% @@ -7949,21 +8396,20 @@ and~\ref{tab:nonisoopts}} %\subsection{Predefined Dialects}\label{sec:predefined} % % Provide some predefined dialects. -%\begin{macro}{\TrackLangDeclareDialectOption} -%\changes{1.3}{2016-10-07}{new} +%\begin{macro}{\TrackLangProvidePredefinedDialect} +%\changes{1.4}{2019-11-30}{new} %\begin{definition} -%\cs{TrackLangDeclareDialectOption}\marg{dialect}\marg{root +%\cs{TrackLangProvidePredefinedDialect}\marg{dialect}\marg{root %language}\marg{3166-1 %code}\marg{modifier}\marg{variant}\marg{map}\marg{script} %\end{definition} -%The option name is the same as the dialect name. The arguments +%This defines a predefined dialect label that can be used +%by \cs{TrackPredefinedDialect}. The arguments %must be expanded before use. The final argument \meta{map} is the %mapping from \meta{dialect} to the closest \styfmt{babel} dialect -%label. May be empty if no relevant mapping. +%label. % \begin{macrocode} -\def\TrackLangDeclareDialectOption#1#2#3#4#5#6#7{% - \@tracklang@ifundef{@tracklang@add@#1}% - {% +\def\TrackLangProvidePredefinedDialect#1#2#3#4#5#6#7{ \ifx\relax#3\relax % \end{macrocode} % No region. @@ -8108,6 +8554,26 @@ and~\ref{tab:nonisoopts}} \expandafter\def\csname @tracklang@add@#1\expandafter\endcsname \expandafter{\@tracklang@tmp\SetTrackedDialectScript{#1}{#7}}% \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TrackLangDeclareDialectOption} +%\changes{1.3}{2016-10-07}{new} +%\begin{definition} +%\cs{TrackLangDeclareDialectOption}\marg{dialect}\marg{root +%language}\marg{3166-1 +%code}\marg{modifier}\marg{variant}\marg{map}\marg{script} +%\end{definition} +%The option name is the same as the dialect name. The arguments +%must be expanded before use. The final argument \meta{map} is the +%mapping from \meta{dialect} to the closest \styfmt{babel} dialect +%label. May be empty if no relevant mapping. +% \begin{macrocode} +\def\TrackLangDeclareDialectOption#1#2#3#4#5#6#7{% + \@tracklang@ifundef{@tracklang@add@#1}% + {% + \TrackLangProvidePredefinedDialect{#1}{#2}{#3}{#4}{#5}{#6}{#7}% \@tracklang@declareoption{#1}% }% {% @@ -9369,21 +9835,20 @@ and~\ref{tab:nonisoopts}} %part}\marg{false part} %\end{definition} % Determines if the file \meta{prefix}\meta{tag}\meta{suffix} -% exists, where \meta{tag} is an ISO code or ISO codes identifying +% exists, where \meta{tag} is an ISO code or ISO codes or label identifying % the language. If \meta{dialect} hasn't been identified % as a tracked dialect, this just does \meta{false part}, -% otherwise this first tries with \meta{tag} set to -% \meta{dialect}, then tries with \meta{tag} set to the root -% language label for \meta{dialect}, then tries with \meta{tag} set to \meta{ISO -% 639-1 code}\texttt{-}\meta{ISO 3166-1 code}, then tries with -% \meta{tag} set to \meta{ISO 639-1 code}, then tries with -% \meta{tag} set to \meta{ISO 639-2 code}\texttt{-}\meta{ISO 3166-1 -% code}, then tries with \meta{tag} set to \meta{ISO 639-2 code}. +% otherwise this tries various different combinations for \meta{tag}. % If the file \meta{prefix}\meta{tag}\meta{suffix} exists, % \cs{CurrentTrackedTag} is set to \meta{tag} and \meta{true part} % is performed, otherwise \meta{false part} is performed. +% The order of priority has changed with version 1.4 and now +% includes a check for variations that include the script. If the +% original ordering is specifically required, the old behaviour can +% be obtained with \cs{IfTrackedLanguageFileExists@orig}. % \begin{macrocode} \long\def\IfTrackedLanguageFileExists#1#2#3#4#5{% + \@tracklang@verbose{Finding file for dialect `#1'}% % \end{macrocode} %Initialise. % \begin{macrocode} @@ -9395,16 +9860,1756 @@ and~\ref{tab:nonisoopts}} \IfTrackedDialect{#1}% {% % \end{macrocode} -% Try just the dialect label. +% Save the three types of language codes to for reference. % \begin{macrocode} + \edef\CurrentTrackedIsoCodeI{\TrackedIsoCodeFromLanguage + {639-1}{\CurrentTrackedLanguage}}% + \edef\CurrentTrackedIsoCodeII{\TrackedIsoCodeFromLanguage + {639-2}{\CurrentTrackedLanguage}}% + \edef\CurrentTrackedIsoCodeIII{\TrackedIsoCodeFromLanguage + {639-3}{\CurrentTrackedLanguage}}% +% \end{macrocode} +%\changes{1.4}{2019-11-30}{added check for scripts} +% Earlier versions of this had too many nested conditionals, which +% was confusing and hard to follow. This is a rewrite that removes +% the nesting and adds extra checks for dialect scripts. +% \begin{macrocode} + \@tracklang@test@if@file@exists@for@tag{#1}{#2}{#3}% + \@tracklang@if@file@exists{#4}{#5}% + }% + {#5}% unknown dialect +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@noop} +%\changes{1.4}{2019-11-30}{new} +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@noop#1#2#3{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@tag} +%\changes{1.4}{2019-11-30}{new} +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@tag#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedLanguageTag + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@if@file@exists\@tracklang@secondoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@dialect + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@dialect} +%\changes{1.4}{2019-11-30}{new} +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@dialect#1#2#3{% + \edef\CurrentTrackedTag{#1}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \IfTrackedLanguageHasIsoCode{639-1}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIscriptregion + }% + {% + \IfTrackedLanguageHasIsoCode{639-2}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIscriptregion + }% + {% + \IfTrackedLanguageHasIsoCode{639-3}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscriptregion + }% + {% + \let\CurrentTrackedIsoCode\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@scriptregion + }% + }% + }% + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIscriptregion} +%\changes{1.4}{2019-11-30}{new} +% Test \meta{639-1}-\meta{sublang}-\meta{script}-\meta{region} combination. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIscriptregion#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeI + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \ifx\CurrentTrackedDialectScript\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \fi + \ifx\CurrentTrackedRegion\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedRegion}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedRegion\empty + \ifx\CurrentTrackedDialectScript\empty +% \end{macrocode} +%No script or region set. If there's a sub-language code then try +%again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langII + \else + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langII + }% + \fi + \else +% \end{macrocode} +%No region set. If there's a sub-language code then try +%again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIskipscript + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIskipscript + }% + \fi + \fi + \else + \ifx\CurrentTrackedDialectScript\empty +% \end{macrocode} +% Region is set but no script. If there's a sub-language code +% then try again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIskipregion + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIskipregion + }% + \fi + \else +% \end{macrocode} +% Region and script set. If there's a sub-language code +% then try again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIskipscriptregion + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript + -\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIskipscriptregion + }% + \fi + \fi + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIscriptregion} +%\changes{1.4}{2019-11-30}{new} +% Test \meta{639-2}-\meta{sublang}-\meta{script}-\meta{region} combination. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIscriptregion#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \ifx\CurrentTrackedDialectScript\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \fi + \ifx\CurrentTrackedRegion\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedRegion}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedRegion\empty + \ifx\CurrentTrackedDialectScript\empty +% \end{macrocode} +%No script or region set. If there's a sub-language code then try +%again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIII + \else + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIII + }% + \fi + \else +% \end{macrocode} +%No region set. If there's a sub-language code then try +%again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipscript + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipscript + }% + \fi + \fi + \else + \ifx\CurrentTrackedDialectScript\empty +% \end{macrocode} +% Region is set but no script. If there's a sub-language code +% then try again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipregion + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipregion + }% + \fi + \else +% \end{macrocode} +% Both region and script are set. If there's a sub-language code +% then try again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipscriptregion + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript + -\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipscriptregion + }% + \fi + \fi + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIscriptregion} +%\changes{1.4}{2019-11-30}{new} +% Test \meta{639-3}-\meta{sublang}-\meta{script}-\meta{region} combination. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIIscriptregion#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \ifx\CurrentTrackedDialectScript\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \fi + \ifx\CurrentTrackedRegion\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedRegion}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedRegion\empty + \ifx\CurrentTrackedDialectScript\empty +% \end{macrocode} +%No script or region set. If there's a sub-language code then try +%again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + \else + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + \fi + \else +% \end{macrocode} +%No region set. If there's a sub-language code then try +%again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipscript + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipscript + }% + \fi + \fi + \else + \ifx\CurrentTrackedDialectScript\empty +% \end{macrocode} +% Region is set but no script. If there's a sub-language code +% then try again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipregion + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipregion + }% + \fi + \else +% \end{macrocode} +% Both region and script are set. If there's a sub-language code +% then try again without it. +% \begin{macrocode} + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipscriptregion + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript + -\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipscriptregion + }% + \fi + \fi + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIskipscript} +%\changes{1.4}{2019-11-30}{new} +%No region. Has a script but already tested with 639-1 and script. +%Just test language code alone. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIskipscript#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \IfTrackedLanguageHasIsoCode + {639-2}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIscript + }% + {% + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscript + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + }% + \else +% \end{macrocode} +% Try without sub-language code. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \IfTrackedLanguageHasIsoCode + {639-2}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIscript + }% + {% + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscript + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + }% + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIscript} +%\changes{1.4}{2019-11-30}{new} +%No region but has a script. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIscript#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipscript + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipscript + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIskipscript} +%\changes{1.4}{2019-11-30}{new} +%No region. Has a script but already checked. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIskipscript#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscript + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscript + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIscript} +%\changes{1.4}{2019-11-30}{new} +%No region but has a script. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIIscript#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipscript + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipscript + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIskipscript} +%\changes{1.4}{2019-11-30}{new} +%No region. Has a script but already checked. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIIskipscript#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIskipregion} +%\changes{1.4}{2019-11-30}{new} +%No script. Has a region but already tested with 639-1 and script. +%Just test language code alone. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \IfTrackedLanguageHasIsoCode + {639-2}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIregion + }% + {% + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIregion + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + }% + \else +% \end{macrocode} +% Try without sub-language code. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \IfTrackedLanguageHasIsoCode + {639-2}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIregion + }% + {% + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIregion + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + }% + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIregion} +%\changes{1.4}{2019-11-30}{new} +%No script but has a region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIregion#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipregion + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIskipregion} +%\changes{1.4}{2019-11-30}{new} +%No script. Has a region but already tested with 639-2 and region. +%Just test language code alone. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIregion + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + \else +% \end{macrocode} +% Try without sub-language code. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIregion + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIregion} +%\changes{1.4}{2019-11-30}{new} +%No script but has a region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIregion#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipregion + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIskipregion} +%\changes{1.4}{2019-11-30}{new} +%No script. Has a region but already tested with 639-3 and region. +%Just test language code alone. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + \else +% \end{macrocode} +% Try without sub-language code. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIregion} +%\changes{1.4}{2019-11-30}{new} +%No script but has a region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIIregion#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipregion + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIskipscriptregion} +%\changes{1.4}{2019-11-30}{new} +%Already tested script and region. Test without script if the script +%is the default then without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIskipscriptregion#1#2#3{% +% \end{macrocode} +% Is the script the default for this dialect? +% \begin{macrocode} + \@tracklang@ifcseqcsname\CurrentTrackedDialectScript + {@tracklang@knowniso@script@\CurrentTrackedLanguage}% + {% +% \end{macrocode} +% Try just language code and region. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% Try just language code and script. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIscriptskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIscriptskipregion + }% + \fi + }% + }% + {% +% \end{macrocode} +% Script isn't the default. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIscriptskipregion + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIscriptskipregion} +%\changes{1.4}{2019-11-30}{new} +%Test with script and without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIscriptskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% Try just language code. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIskipscriptskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIskipscriptskipregion + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIskipscriptskipregion} +%\changes{1.4}{2019-11-30}{new} +%Test without script and without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIskipscriptskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% Try other language codes with script and region. +% \begin{macrocode} + \IfTrackedLanguageHasIsoCode + {639-2}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIscriptregion + }% + {% + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscriptregion + }% + {% +% \end{macrocode} +% No other language codes. Try just the region. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@region + }% + }% + \else +% \end{macrocode} +% Try just language code. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% +% \end{macrocode} +% Try other language codes with script and region. +% \begin{macrocode} + \IfTrackedLanguageHasIsoCode + {639-2}{\CurrentTrackedLanguage} + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIscriptregion + }% + {% + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscriptregion + }% + {% +% \end{macrocode} +% No other language codes. Try just the region. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@region + }% + }% + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIskipscriptregion} +%\changes{1.4}{2019-11-30}{new} +%Already tested script and region. Test without script if the script +%is the default then without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIskipscriptregion#1#2#3{% +% \end{macrocode} +% Is the script the default for this dialect? +% \begin{macrocode} + \@tracklang@ifcseqcsname\CurrentTrackedDialectScript + {@tracklang@knowniso@script@\CurrentTrackedLanguage}% + {% +% \end{macrocode} +% Try just language code and region. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% Try just language code and script. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIscriptskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIscriptskipregion + }% + \fi + }% + }% + {% +% \end{macrocode} +% Script isn't the default. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIscriptskipregion + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIscriptskipregion} +%\changes{1.4}{2019-11-30}{new} +%Test with script and without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIscriptskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% Try just language code. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipscriptskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIskipscriptskipregion + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIskipscriptskipregion} +%\changes{1.4}{2019-11-30}{new} +%Test without script and without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIskipscriptskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% Try other language code with script and region. +% \begin{macrocode} + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscriptregion + }% + {% +% \end{macrocode} +% No other language codes. Try just the region. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@region + }% + \else +% \end{macrocode} +% Try just language code. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% +% \end{macrocode} +% Try other language codes with script and region. +% \begin{macrocode} + \IfTrackedLanguageHasIsoCode + {639-3}{\CurrentTrackedLanguage} + {% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscriptregion + }% + {% +% \end{macrocode} +% No other language codes. Try just the region. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@region + }% + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIskipscriptregion} +%\changes{1.4}{2019-11-30}{new} +%Already tested script and region. Test without script if the script +%is the default then without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIIskipscriptregion#1#2#3{% +% \end{macrocode} +% Is the script the default for this dialect? +% \begin{macrocode} + \@tracklang@ifcseqcsname\CurrentTrackedDialectScript + {@tracklang@knowniso@script@\CurrentTrackedLanguage}% + {% +% \end{macrocode} +% Try just language code and region. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% Try just language code and script. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscriptskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedRegion}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscriptskipregion + }% + \fi + }% + }% + {% +% \end{macrocode} +% Script isn't the default. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIscriptskipregion + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIscriptskipregion} +%\changes{1.4}{2019-11-30}{new} +%Test with script and without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIIscriptskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% Try just language code. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipscriptskipregion + \else +% \end{macrocode} +% Try without sub-language. +% \begin{macrocode} + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectScript}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIskipscriptskipregion + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIskipscriptskipregion} +%\changes{1.4}{2019-11-30}{new} +%Test without script and without region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIIskipscriptskipregion#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty +% \end{macrocode} +% No other language codes. Try just the region. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@region + \else +% \end{macrocode} +% Try just language code. +% \begin{macrocode} + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% +% \end{macrocode} +% No other language codes. Try just the region. +% \begin{macrocode} + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@region + }% + \fi + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langII} +%\changes{1.4}{2019-11-30}{new} +%No region or script. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langII#1#2#3{% + \IfTrackedLanguageHasIsoCode{639-2}{\CurrentTrackedLanguage}% + {% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeII + \ifx\CurrentTrackedDialectSubLang\empty + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIII + \else + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIII + }% + \fi + }% + {% + \fi + }% + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIII + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIII} +%\changes{1.4}{2019-11-30}{new} +%No region or script. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIII#1#2#3{% + \IfTrackedLanguageHasIsoCode{639-3}{\CurrentTrackedLanguage}% + {% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \ifx\CurrentTrackedDialectSubLang\empty + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \else + \edef\CurrentTrackedTag{\CurrentTrackedIsoCode-\CurrentTrackedDialectSubLang}% + \fi + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \ifx\CurrentTrackedDialectSubLang\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + \else + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + \fi + }% + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@region} +%\changes{1.4}{2019-11-30}{new} +%Test just the region. +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@region#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedRegion + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langvariant + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langvariant} +%\changes{1.4}{2019-11-30}{new} +%Test language code and variant +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langvariant#1#2#3{% + \ifx\CurrentTrackedDialectVariant\empty + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@rootlang + \else + \IfTrackedLanguageHasIsoCode{639-1}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIvariant + }% + {% + \IfTrackedLanguageHasIsoCode{639-2}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIvariant + }% + {% + \IfTrackedLanguageHasIsoCode{639-3}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIvariant + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@rootlang + }% + }% + }% + \fi + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIvariant} +%\changes{1.4}{2019-11-30}{new} +%Test 639-1 code and variant +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIvariant#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeI + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectVariant}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \IfTrackedLanguageHasIsoCode{639-2}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIvariant + } + {% + \IfTrackedLanguageHasIsoCode{639-3}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIvariant + } + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@rootlang + }% + }% + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIvariant} +%\changes{1.4}{2019-11-30}{new} +%Test 639-2 code and variant +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIvariant#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectVariant}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \IfTrackedLanguageHasIsoCode{639-3}{\CurrentTrackedLanguage}% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@langIIIvariant + } + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@rootlang + }% + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@langIIIvariant} +%\changes{1.4}{2019-11-30}{new} +%Test 639-3 code and variant +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@langIIIvariant#1#2#3{% + \let\CurrentTrackedIsoCode\CurrentTrackedIsoCodeIII + \let\CurrentTrackedTag\CurrentTrackedIsoCode + \ifx\CurrentTrackedDialectSubLang\empty + \else + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectSubLang}% + \fi + \edef\CurrentTrackedTag{\CurrentTrackedTag-\CurrentTrackedDialectVariant}% + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@noop + }% + {% + \let\@tracklang@test@if@file@exists@next\@tracklang@test@if@file@exists@for@rootlang + }% + \@tracklang@test@if@file@exists@next{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@test@if@file@exists@for@rootlang} +%\changes{1.4}{2019-11-30}{new} +%Test the root language label. (Final test.) +% \begin{macrocode} +\def\@tracklang@test@if@file@exists@for@rootlang#1#2#3{% + \let\CurrentTrackedTag\CurrentTrackedLanguage + \@tracklang@verbose{Testing tag `\CurrentTrackedTag'}% + \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% + {% + \let\@tracklang@if@file@exists\@tracklang@firstoftwo + }% + {}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\IfTrackedLanguageFileExists@orig} +%\changes{1.4}{2019-11-30}{new} +%The new definition of \cs{IfTrackedLanguageFileExists} has a +%different order of priority. If the original behaviour is +%specifically required, this has the pre version 1.4 definition. +% \begin{macrocode} +\long\def\IfTrackedLanguageFileExists@orig#1#2#3#4#5{% + \def\CurrentTrackedTag{}% + \SetCurrentTrackedDialect{#1}% + \IfTrackedDialect{#1}% + {% \edef\CurrentTrackedTag{#1}% \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% No file found for dialect label, try \meta{ISO 639-1}-\meta{ISO -% 3166-1} next. -% \begin{macrocode} \IfTrackedLanguageHasIsoCode {639-1}{\CurrentTrackedLanguage} {% @@ -9412,17 +11617,10 @@ and~\ref{tab:nonisoopts}} \TrackedIsoCodeFromLanguage {639-1}{\CurrentTrackedLanguage}}% \ifx\CurrentTrackedRegion\empty -% \end{macrocode} -% No region, just try ISO 639-1 code -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedIsoCode \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4} {% -% \end{macrocode} -% No region and file for just \meta{ISO 639-1 code}. Try ISO 639-2 code. -% (No check for 639-3 since it has 639-1 code.) -% \begin{macrocode} \IfTrackedLanguageHasIsoCode {639-2}{\CurrentTrackedLanguage} {% @@ -9433,35 +11631,21 @@ and~\ref{tab:nonisoopts}} \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Try root language. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedLanguage \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}{#4}{#5}% }% }% {% -% \end{macrocode} -% No region, no ISO 639-1 code and no ISO 639-2 code. -% No file found for dialect label, try root language label next. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedLanguage \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}{#4}{#5}% }% }% \else -% \end{macrocode} -% Has a region so try \meta{ISO 639-1 code}\texttt{-}\meta{region} -% \begin{macrocode} \edef\CurrentTrackedTag{% \CurrentTrackedIsoCode-\CurrentTrackedRegion}% \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4} {% -% \end{macrocode} -% Has a region but \meta{ISO 639-1 code}\texttt{-}\meta{region} -% not found, so try \meta{ISO 639-2 code}\texttt{-}\meta{region} -% \begin{macrocode} \IfTrackedLanguageHasIsoCode {639-2}{\CurrentTrackedLanguage} {% @@ -9474,35 +11658,21 @@ and~\ref{tab:nonisoopts}} \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Has a region but \meta{ISO 639-1 code}\texttt{-}\meta{region} not -% found and \meta{ISO 639-2 code}\texttt{-}\meta{region} not found, -% so try just \meta{ISO 639-1 code} -% \begin{macrocode} \let\CurrentTrackedTag\org@currenttrackedisocode \let\org@currenttrackedisocode\CurrentTrackedIsoCode \let\CurrentTrackedIsoCode\CurrentTrackedTag \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4} {% -% \end{macrocode} -% Try just the ISO 639-2 code. -% \begin{macrocode} \let\CurrentTrackedIsoCode\org@currenttrackedisocode \let\CurrentTrackedTag\CurrentTrackedIsoCode \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Try just the region. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedRegion \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Try the root language. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedLanguage \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}{#4}{#5}% }% @@ -9511,24 +11681,14 @@ and~\ref{tab:nonisoopts}} }% }% {% -% \end{macrocode} -% Has a region but \meta{ISO 639-1 code}\texttt{-}\meta{region} -% not found, and no ISO 639-2 code so just try \meta{ISO 639-1 code} -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedIsoCode \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Just try the region -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedRegion \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Try the root language. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedLanguage \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}{#4}{#5}% }% @@ -9538,9 +11698,6 @@ and~\ref{tab:nonisoopts}} \fi }% {% -% \end{macrocode} -% No ISO 639-1 code. Try ISO 639-2 code. -% \begin{macrocode} \IfTrackedLanguageHasIsoCode {639-2}{\CurrentTrackedLanguage} {% @@ -9549,9 +11706,6 @@ and~\ref{tab:nonisoopts}} {639-2}{\CurrentTrackedLanguage}}% }% {% -% \end{macrocode} -% No ISO 639-1 code or ISO 639-2 code. Try 639-3 code. -% \begin{macrocode} \IfTrackedLanguageHasIsoCode {639-3}{\CurrentTrackedLanguage} {% @@ -9564,78 +11718,41 @@ and~\ref{tab:nonisoopts}} }% }% \ifx\CurrentTrackedIsoCode\empty -% \end{macrocode} -% No ISO 639-1 code or ISO 639-2 code. Try just the region. -% \begin{macrocode} \ifx\CurrentTrackedRegion\empty -% \end{macrocode} -% No region. Try the root language. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedLanguage \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}{#4}{#5}% \else -% \end{macrocode} -% Try the region. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedRegion \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Try the root language. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedLanguage \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}{#4}{#5}% }% \fi \else -% \end{macrocode} -% Has ISO 639-2 or 639-3 code. -% \begin{macrocode} \ifx\CurrentTrackedRegion\empty -% \end{macrocode} -% Has ISO 639-2 or 639-3 code but no region. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedIsoCode \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Try the root language. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedLanguage \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}{#4}{#5}% }% \else -% \end{macrocode} -% Has ISO 639-2 or 639-3 code and a region. Try \meta{ISO -% 639-2 or 639-3}\texttt{-}\meta{region} first. -% \begin{macrocode} \edef\CurrentTrackedTag{% \CurrentTrackedIsoCode-\CurrentTrackedRegion}% \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Has ISO 639-2 or 639-3 code and a region but \meta{ISO -% 639-2 or 639-3}\texttt{-}\meta{region} doesn't exist. Try just \meta{ISO -% 639-2 or 639-3} -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedIsoCode \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Has ISO 639-2 or 639-3 code and a region but \meta{ISO -% 639-2 or 639-3} doesn't exist. Try just \meta{region} -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedRegion \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}% {#4}% {% -% \end{macrocode} -% Try the root language. -% \begin{macrocode} \let\CurrentTrackedTag\CurrentTrackedLanguage \@tracklang@IfFileExists{#2\CurrentTrackedTag#3}{#4}{#5}% }% @@ -9838,6 +11955,102 @@ and~\ref{tab:nonisoopts}} % \end{macrocode} %\end{macro} % +%\begin{macro}{\TrackLangRedefHook} +%\changes{1.4}{2019-11-30}{new} +%\begin{definition} +%\cs{TrackLangRedefHook}\marg{code}\marg{type} +%\end{definition} +% Similar to \cs{TrackLangAddToHook} but redefines the hook rather +% than appending to it. +% This command is not permitted outside resource files. +% \begin{macrocode} +\def\TrackLangRedefHook{\noop@TrackLangRedefHook} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\noop@TrackLangRedefHook} +% \begin{macrocode} +\def\noop@TrackLangRedefHook#1#2{% + \@tracklang@err{\string\TrackLangRedefHook\space + only permitted within resource files} +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@TrackLangRedefHook} +% \begin{macrocode} +\def\@TrackLangRedefHook#1#2{% +% \end{macrocode} +% \sty{babel} check first. +% \begin{macrocode} + \@tracklang@ifundef{#2\CurrentTrackedDialect}% + {% +% \end{macrocode} +% Does the dialect label have a mapping? +% \begin{macrocode} + \IfTrackedDialectHasMapping{\CurrentTrackedDialect}% + {% +% \end{macrocode} +% Try the mapping label next. +% \begin{macrocode} + \edef\@tracklang@tmp{% + \csname @tracklang@dialectmap@tohook@\CurrentTrackedDialect\endcsname}% + \@tracklang@ifundef{#2\@tracklang@tmp}% + {% +% \end{macrocode} +% No captions hook. Try \sty{polyglossia}. +% \begin{macrocode} + \@tracklang@ifundef{#2\CurrentTrackedLanguage}% + {% +% \end{macrocode} +% No captions hook. Do the code now. +% \begin{macrocode} + #1% + }% + {% + \@tracklang@redefhook{#2}{\CurrentTrackedLanguage}{#1}% + }% + }% + {% + \@tracklang@redefhook{#2}{\@tracklang@tmp}{#1}% + }% + }% + {% +% \end{macrocode} +% \sty{polyglossia} check next. +% \begin{macrocode} + \@tracklang@ifundef{#2\CurrentTrackedLanguage}% + {% +% \end{macrocode} +% No captions hook. +% \begin{macrocode} + }% + {% + \@tracklang@redefhook{#2}{\CurrentTrackedLanguage}{#1}% + }% + }% + }% + {% + \@tracklang@redefhook{#2}{\CurrentTrackedDialect}{#1}% + }% +% \end{macrocode} +% Do the code now in case the hook has already been used. +% \begin{macrocode} + #1% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@tracklang@redefhook} +%\changes{1.4}{2019-11-30}{new} +%\begin{definition} +%\cs{@tracklang@redefhook}\marg{type}\marg{label}\marg{code} +%\end{definition} +% \begin{macrocode} +\def\@tracklang@redefhook#1#2#3{% + \expandafter\gdef\csname#1#2\endcsname{#3}% +} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\SetTrackedDialectLabelMap} %\changes{1.3}{2016-10-07}{new} %\begin{definition} @@ -10193,7 +12406,7 @@ and~\ref{tab:nonisoopts}} % Version info. % \begin{macrocode} \expandafter\def\csname ver@tracklang-region-codes.tex\endcsname{% - 2019/11/11 v1.3.9 (NLCT) Track Languages Regions}% + 2019/11/30 v1.4 (NLCT) Track Languages Regions}% % \end{macrocode} % %\begin{macro}{\TrackLangRegionMap} @@ -10560,6 +12773,10 @@ and~\ref{tab:nonisoopts}} \TrackLangRegionMap{894}{ZM}{ZMB}% \TrackLangRegionMap{716}{ZW}{ZWE}% % \end{macrocode} +%\changes{1.4}{2019-11-30}{input extra regions if provided} +% \begin{macrocode} +\@tracklang@input@extra@region@files +% \end{macrocode} % %Restore category code of \texttt{@}. % \begin{macrocode} @@ -10582,7 +12799,7 @@ and~\ref{tab:nonisoopts}} %\changes{1.3}{2016-10-07}{added tracklang-scripts.sty} % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{tracklang-scripts}[2019/11/11 v1.3.9 (NLCT) Track +\ProvidesPackage{tracklang-scripts}[2019/11/30 v1.4 (NLCT) Track Language Scripts (LaTeX)] \RequirePackage{tracklang} \input{tracklang-scripts} @@ -10624,7 +12841,7 @@ Language Scripts (LaTeX)] % Version info. % \begin{macrocode} \expandafter\def\csname ver@tracklang-scripts.tex\endcsname{% - 2019/11/11 v1.3.9 (NLCT) Track Languages Scripts (Generic)}% + 2019/11/30 v1.4 (NLCT) Track Languages Scripts (Generic)}% % \end{macrocode} % %\begin{macro}{\TrackLangScriptsMap} @@ -10785,202 +13002,197 @@ Language Scripts (LaTeX)] %\end{macro} % %Define mappings. The parent information is currently missing. -% \begin{macrocode} -\TrackLangScriptMap{Adlm}{166}{Adlam}{RL}{} -\TrackLangScriptMap{Afak}{439}{Afaka}{varies}{} -\TrackLangScriptMap{Aghb}{239}{Caucasian Albanian}{LR}{} -\TrackLangScriptMap{Ahom}{338}{Ahom, Tai Ahom}{LR}{} -\TrackLangScriptMap{Arab}{160}{Arabic}{RL}{} -\TrackLangScriptMap{Aran}{161}{Arabic (Nastaliq variant)}{RL}{} -\TrackLangScriptMap{Armi}{124}{Imperial Aramaic}{RL}{} -\TrackLangScriptMap{Armn}{230}{Armenian}{LR}{} -\TrackLangScriptMap{Avst}{134}{Avestan}{RL}{} -\TrackLangScriptMap{Bali}{360}{Balinese}{LR}{} -\TrackLangScriptMap{Bamu}{435}{Bamum}{LR}{} -\TrackLangScriptMap{Bass}{259}{Bassa Vah}{LR}{} -\TrackLangScriptMap{Batk}{365}{Batak}{LR}{} -\TrackLangScriptMap{Beng}{334}{Bhaiksuki}{LR}{} -\TrackLangScriptMap{Blis}{550}{Blissymbols}{varies}{} -\TrackLangScriptMap{Bopo}{285}{Bopomofo}{LR}{} -\TrackLangScriptMap{Brah}{300}{Brahmi}{LR}{} -\TrackLangScriptMap{Brai}{570}{Braille}{LR}{} -\TrackLangScriptMap{Bugi}{367}{Buginese}{LR}{} -\TrackLangScriptMap{Buhd}{372}{Buhid}{LR}{} -\TrackLangScriptMap{Cakm}{349}{Chakma}{LR}{} -\TrackLangScriptMap{Cans}{440}{Unified Canadian Aboriginal Syllabics}{LR}{} -\TrackLangScriptMap{Cari}{201}{Carian}{LR}{} -\TrackLangScriptMap{Cham}{358}{Cham}{LR}{} -\TrackLangScriptMap{Cher}{445}{Cherokee}{LR}{} -\TrackLangScriptMap{Cirt}{291}{Cirth}{varies}{} -\TrackLangScriptMap{Copt}{204}{Coptic}{LR}{} -\TrackLangScriptMap{Cprt}{403}{Cypriot}{RL}{} -\TrackLangScriptMap{Cyrl}{220}{Cyrillic}{LR}{} -\TrackLangScriptMap{Cyrs}{221}{Cyrillic (Old Church Slavonic{} -variant)}{varies}{} -\TrackLangScriptMap{Deva}{315}{Devanagari (Nagari)}{LR}{} -\TrackLangScriptMap{Dsrt}{250}{Deseret (Mormon)}{LR}{} -\TrackLangScriptMap{Dupl}{755}{Duployan shorthand, Duployan{} -stenography}{LR}{} -\TrackLangScriptMap{Egyd}{070}{Egyptian demotic}{RL}{} -\TrackLangScriptMap{Egyh}{060}{Egyptian hieratic}{RL}{} -\TrackLangScriptMap{Egyp}{050}{Egyptian hieroglyphs}{LR}{} -\TrackLangScriptMap{Elba}{226}{Elbasan}{LR}{} -\TrackLangScriptMap{Ethi}{430}{Ethiopic (Ge'ez)}{LR}{} -\TrackLangScriptMap{Geok}{241}{Khutsuri (Asomtavruli and{} -Nuskhuri)}{LR}{} -\TrackLangScriptMap{Geor}{240}{Georgian (Mkhedruli)}{LR}{} -\TrackLangScriptMap{Glag}{225}{Glagolitic}{LR}{} -\TrackLangScriptMap{Goth}{206}{Gothic}{LR}{} -\TrackLangScriptMap{Gran}{343}{Grantha}{LR}{} -\TrackLangScriptMap{Grek}{200}{Greek}{LR}{} -\TrackLangScriptMap{Gujr}{320}{Gujarati}{LR}{} -\TrackLangScriptMap{Guru}{310}{Gurmukhi}{LR}{} -\TrackLangScriptMap{Hanb}{503}{Han with Bopomofo (alias for Han +{} -Bopomofo)}{LR}{} -\TrackLangScriptMap{Hang}{286}{Hangul}{LR}{} -\TrackLangScriptMap{Hani}{500}{Han (Hanzi, Kanji, Hanja)}{LR}{} -\TrackLangScriptMap{Hano}{371}{Hanunoo}{LR}{} -\TrackLangScriptMap{Hans}{501}{Han (Simplified variant)}{varies}{} -\TrackLangScriptMap{Hant}{502}{Han (Traditional variant)}{varies}{} -\TrackLangScriptMap{Hatr}{127}{Hatran}{RL}{} -\TrackLangScriptMap{Hebr}{125}{Hebrew}{RL}{} -\TrackLangScriptMap{Hira}{410}{Hiragana}{LR}{} -\TrackLangScriptMap{Hluw}{080}{Anatolian Hieroglyphs (Luwian{} -Hieroglyphs, Hittite Hieroglyphs)}{LR}{} -\TrackLangScriptMap{Hmng}{450}{Pahawh Hmong}{LR}{} -\TrackLangScriptMap{Hrkt}{412}{Japanese syllabaries (alias for{} -Hiragana + Katakana)}{varies}{} -\TrackLangScriptMap{Hung}{176}{Old Hungarian (Hungarian Runic)}{RL}{} -\TrackLangScriptMap{Inds}{610}{Indus (Harappan)}{RL}{} -\TrackLangScriptMap{Ital}{210}{Old Italic (Etruscan, Oscan, etc.)}{LR}{} -\TrackLangScriptMap{Jamo}{284}{Jamo (alias for Jamo subset of{} -Hangul)}{LR}{} -\TrackLangScriptMap{Java}{361}{Javanese}{LR}{} -\TrackLangScriptMap{Jpan}{413}{Japanese (alias for Han + Hiragana +{} -Katakana)}{varies}{} -\TrackLangScriptMap{Jurc}{510}{Jurchen}{LR}{} -\TrackLangScriptMap{Kali}{357}{Kayah Li}{LR}{} -\TrackLangScriptMap{Kana}{411}{Katakana}{LR}{} -\TrackLangScriptMap{Khar}{305}{Kharoshthi}{RL}{} -\TrackLangScriptMap{Khmr}{355}{Khmer}{LR}{} -\TrackLangScriptMap{Khoj}{322}{Khojki}{LR}{} -\TrackLangScriptMap{Kitl}{505}{Khitan large script}{LR}{} -\TrackLangScriptMap{Kits}{288}{Khitan small script}{TB}{} -\TrackLangScriptMap{Knda}{345}{Kannada}{LR}{} -\TrackLangScriptMap{Kore}{287}{Korean (alias for Hangul + Han)}{LR}{} -\TrackLangScriptMap{Kpel}{436}{Kpelle}{LR}{} -\TrackLangScriptMap{Kthi}{317}{Kaithi}{LR}{} -\TrackLangScriptMap{Lana}{351}{Tai Tham (Lanna)}{LR}{} -\TrackLangScriptMap{Laoo}{356}{Lao}{LR}{} -\TrackLangScriptMap{Latf}{217}{Latin (Fraktur variant)}{varies}{} -\TrackLangScriptMap{Latg}{216}{Latin (Gaelic variant)}{LR}{} -\TrackLangScriptMap{Latn}{215}{Latin}{LR}{} -\TrackLangScriptMap{Leke}{364}{Leke}{LR}{} -\TrackLangScriptMap{Lepc}{335}{Lepcha}{LR}{} -\TrackLangScriptMap{Limb}{336}{Limbu}{LR}{} -\TrackLangScriptMap{Lina}{400}{Linear A}{LR}{} -\TrackLangScriptMap{Linb}{401}{Linear B}{LR}{} -\TrackLangScriptMap{Lisu}{399}{Lisu (Fraser)}{LR}{} -\TrackLangScriptMap{Loma}{437}{Loma}{LR}{} -\TrackLangScriptMap{Lyci}{202}{Lycian}{LR}{} -\TrackLangScriptMap{Lydi}{116}{Lydian}{RL}{} -\TrackLangScriptMap{Mahj}{314}{Mahajani}{LR}{} -\TrackLangScriptMap{Mand}{140}{Mandaic, Mandaean}{RL}{} -\TrackLangScriptMap{Mani}{139}{Manichaean}{RL}{} -\TrackLangScriptMap{Marc}{332}{Marchen}{LR}{} -\TrackLangScriptMap{Maya}{090}{Mayan hieroglyphs}{varies}{} -\TrackLangScriptMap{Mend}{438}{Mende Kikakui}{RL}{} -\TrackLangScriptMap{Merc}{101}{Meroitic Cursive}{RL}{} -\TrackLangScriptMap{Mero}{100}{Meroitic Hieroglyphs}{RL}{} -\TrackLangScriptMap{Mlym}{347}{Malayalam}{LR}{} -\TrackLangScriptMap{Modi}{324}{Modi}{LR}{} -\TrackLangScriptMap{Mong}{145}{Mongolian}{TB}{} -\TrackLangScriptMap{Moon}{218}{Moon (Moon code, Moon script, Moon{} -type)}{varies}{} -\TrackLangScriptMap{Mroo}{199}{Mro, Mru}{LR}{} -\TrackLangScriptMap{Mtei}{337}{Meitei Mayek (Meithei, Meetei)}{LR}{} -\TrackLangScriptMap{Mult}{323}{Multani}{LR}{} -\TrackLangScriptMap{Mymr}{350}{Myanmar (Burmese)}{LR}{} -\TrackLangScriptMap{Narb}{106}{Old North Arabian (Ancient North{} -Arabian)}{RL}{} -\TrackLangScriptMap{Nbat}{159}{Nabataean}{RL}{} -\TrackLangScriptMap{Newa}{333}{Newa, Newar, Newari}{LR}{} -\TrackLangScriptMap{Nkgb}{420}{Nakhi Geba}{LR}{} -\TrackLangScriptMap{Nkoo}{165}{N'Ko}{RL}{} -\TrackLangScriptMap{Nshu}{499}{Nushu}{LR}{} -\TrackLangScriptMap{Ogam}{212}{Ogham}{varies}{} -\TrackLangScriptMap{Olck}{261}{Ol Chiki}{LR}{} -\TrackLangScriptMap{Orkh}{175}{Old Turkic, Orkhon Runic}{RL}{} -\TrackLangScriptMap{Orya}{327}{Oriya}{LR}{} -\TrackLangScriptMap{Osge}{219}{Osage}{LR}{} -\TrackLangScriptMap{Osma}{260}{Osmanya}{LR}{} -\TrackLangScriptMap{Palm}{126}{Palmyrene}{RL}{} -\TrackLangScriptMap{Pauc}{263}{Pau Cin Hau}{LR}{} -\TrackLangScriptMap{Perm}{227}{Old Permic}{LR}{} -\TrackLangScriptMap{Phag}{331}{Phags-pa}{TB}{} -\TrackLangScriptMap{Phli}{131}{Inscriptional Pahlavi}{RL}{} -\TrackLangScriptMap{Phlp}{132}{Psalter Pahlavi}{RL}{} -\TrackLangScriptMap{Phlv}{133}{Book Pahlavi}{RL}{} -\TrackLangScriptMap{Phnx}{115}{Phoenician}{RL}{} -\TrackLangScriptMap{Piqd}{293}{Klingon (KLI plqaD)}{LR}{} -\TrackLangScriptMap{Plrd}{282}{Miao (Pollard)}{LR}{} -\TrackLangScriptMap{Prti}{130}{Inscriptional Parthian}{RL}{} -\TrackLangScriptMap{Qaaa}{900}{Reserved for private use{} -(start)}{varies}{} -\TrackLangScriptMap{Qaai}{908}{Private use}{varies}{} -\TrackLangScriptMap{Qabx}{949}{Reserved for private use{} -(end)}{varies}{} -\TrackLangScriptMap{Rjng}{363}{Rejang (Redjang, Kaganga)}{LR}{} -\TrackLangScriptMap{Roro}{620}{Rongorongo}{varies}{} -\TrackLangScriptMap{Runr}{211}{Runic}{LR}{} -\TrackLangScriptMap{Samr}{123}{Samaritan}{RL}{} -\TrackLangScriptMap{Sara}{292}{Sarati}{varies}{} -\TrackLangScriptMap{Sarb}{105}{Old South Arabian}{RL}{} -\TrackLangScriptMap{Saur}{344}{Saurashtra}{LR}{} -\TrackLangScriptMap{Sgnw}{095}{SignWriting}{TB}{} -\TrackLangScriptMap{Shaw}{281}{Shavian (Shaw)}{LR}{} -\TrackLangScriptMap{Shrd}{319}{Sharada}{LR}{} -\TrackLangScriptMap{Sidd}{302}{Siddham}{LR}{} -\TrackLangScriptMap{Sind}{318}{Khudawadi, Sindhi}{LR}{} -\TrackLangScriptMap{Sinh}{348}{Sinhala}{LR}{} -\TrackLangScriptMap{Sora}{398}{Sora Sompeng}{LR}{} -\TrackLangScriptMap{Sund}{362}{Sundanese}{LR}{} -\TrackLangScriptMap{Sylo}{316}{Syloti Nagri}{LR}{} -\TrackLangScriptMap{Syrc}{135}{Syriac}{RL}{} -\TrackLangScriptMap{Syre}{138}{Syriac (Estrangelo variant)}{RL}{} -\TrackLangScriptMap{Syrj}{137}{Syriac (Western variant)}{RL}{} -\TrackLangScriptMap{Syrn}{136}{Syriac (Eastern variant)}{RL}{} -\TrackLangScriptMap{Tagb}{373}{Tagbanwa}{LR}{} -\TrackLangScriptMap{Takr}{321}{Takri}{LR}{} -\TrackLangScriptMap{Tale}{353}{Tai Le}{LR}{} -\TrackLangScriptMap{Talu}{354}{New Tai Lue}{LR}{} -\TrackLangScriptMap{Taml}{346}{Tamil}{LR}{} -\TrackLangScriptMap{Taml}{346}{Tamil}{LR}{} -\TrackLangScriptMap{Tang}{520}{Tangut}{LR}{} -\TrackLangScriptMap{Tavt}{359}{Tai Viet}{LR}{} -\TrackLangScriptMap{Telu}{340}{Telugu}{LR}{} -\TrackLangScriptMap{Teng}{290}{Tengwar}{LR}{} -\TrackLangScriptMap{Tfng}{120}{Tifinagh (Berber)}{LR}{} -\TrackLangScriptMap{Tglg}{370}{Tagalog (Baybayin, Alibata)}{LR}{} -\TrackLangScriptMap{Thaa}{170}{Thaana}{RL}{} -\TrackLangScriptMap{Thai}{352}{Thai}{LR}{} -\TrackLangScriptMap{Tibt}{330}{Tibetan}{LR}{} -\TrackLangScriptMap{Tirh}{326}{Tirhuta}{LR}{} -\TrackLangScriptMap{Ugar}{040}{Ugaritic}{LR}{} -\TrackLangScriptMap{Vaii}{470}{Vai}{LR}{} -\TrackLangScriptMap{Visp}{280}{Visible Speech}{LR}{} -\TrackLangScriptMap{Wara}{262}{Warang Citi (Varang Kshiti)}{LR}{} -\TrackLangScriptMap{Wole}{480}{Woleai}{RL}{} -\TrackLangScriptMap{Xpeo}{030}{Old Persian}{LR}{} -\TrackLangScriptMap{Xsux}{020}{Cuneiform, Sumero-Akkadian}{LR}{} -\TrackLangScriptMap{Yiii}{460}{Yi}{LR}{} -\TrackLangScriptMap{Zinh}{994}{Inherited script}{inherited}{} -\TrackLangScriptMap{Zmth}{995}{Mathematical notation}{LR}{} -\TrackLangScriptMap{Zsym}{996}{Symbols}{varies}{} -\TrackLangScriptMap{Zsye}{993}{Symbols (emoji variant)}{varies}{} -\TrackLangScriptMap{Zxxx}{997}{Unwritten documents}{varies}{} -\TrackLangScriptMap{Zyyy}{998}{Undetermined script}{varies}{} -\TrackLangScriptMap{Zzzz}{999}{Uncoded script}{varies}{} +%\changes{1.4}{2019-11-30}{removed some spurious empty braces and commented +%out EOL} +% \begin{macrocode} +\TrackLangScriptMap{Adlm}{166}{Adlam}{RL}{}% +\TrackLangScriptMap{Afak}{439}{Afaka}{varies}{}% +\TrackLangScriptMap{Aghb}{239}{Caucasian Albanian}{LR}{}% +\TrackLangScriptMap{Ahom}{338}{Ahom, Tai Ahom}{LR}{}% +\TrackLangScriptMap{Arab}{160}{Arabic}{RL}{}% +\TrackLangScriptMap{Aran}{161}{Arabic (Nastaliq variant)}{RL}{}% +\TrackLangScriptMap{Armi}{124}{Imperial Aramaic}{RL}{}% +\TrackLangScriptMap{Armn}{230}{Armenian}{LR}{}% +\TrackLangScriptMap{Avst}{134}{Avestan}{RL}{}% +\TrackLangScriptMap{Bali}{360}{Balinese}{LR}{}% +\TrackLangScriptMap{Bamu}{435}{Bamum}{LR}{}% +\TrackLangScriptMap{Bass}{259}{Bassa Vah}{LR}{}% +\TrackLangScriptMap{Batk}{365}{Batak}{LR}{}% +\TrackLangScriptMap{Beng}{334}{Bhaiksuki}{LR}{}% +\TrackLangScriptMap{Blis}{550}{Blissymbols}{varies}{}% +\TrackLangScriptMap{Bopo}{285}{Bopomofo}{LR}{}% +\TrackLangScriptMap{Brah}{300}{Brahmi}{LR}{}% +\TrackLangScriptMap{Brai}{570}{Braille}{LR}{}% +\TrackLangScriptMap{Bugi}{367}{Buginese}{LR}{}% +\TrackLangScriptMap{Buhd}{372}{Buhid}{LR}{}% +\TrackLangScriptMap{Cakm}{349}{Chakma}{LR}{}% +\TrackLangScriptMap{Cans}{440}{Unified Canadian Aboriginal Syllabics}{LR}{}% +\TrackLangScriptMap{Cari}{201}{Carian}{LR}{}% +\TrackLangScriptMap{Cham}{358}{Cham}{LR}{}% +\TrackLangScriptMap{Cher}{445}{Cherokee}{LR}{}% +\TrackLangScriptMap{Cirt}{291}{Cirth}{varies}{}% +\TrackLangScriptMap{Copt}{204}{Coptic}{LR}{}% +\TrackLangScriptMap{Cprt}{403}{Cypriot}{RL}{}% +\TrackLangScriptMap{Cyrl}{220}{Cyrillic}{LR}{}% +\TrackLangScriptMap{Cyrs}{221}{Cyrillic (Old Church Slavonic variant)}{varies}{}% +\TrackLangScriptMap{Deva}{315}{Devanagari (Nagari)}{LR}{}% +\TrackLangScriptMap{Dsrt}{250}{Deseret (Mormon)}{LR}{}% +\TrackLangScriptMap{Dupl}{755}{Duployan shorthand, Duployan stenography}{LR}{}% +\TrackLangScriptMap{Egyd}{070}{Egyptian demotic}{RL}{}% +\TrackLangScriptMap{Egyh}{060}{Egyptian hieratic}{RL}{}% +\TrackLangScriptMap{Egyp}{050}{Egyptian hieroglyphs}{LR}{}% +\TrackLangScriptMap{Elba}{226}{Elbasan}{LR}{}% +\TrackLangScriptMap{Ethi}{430}{Ethiopic (Ge'ez)}{LR}{}% +\TrackLangScriptMap{Geok}{241}{Khutsuri (Asomtavruli and Nuskhuri)}{LR}{}% +\TrackLangScriptMap{Geor}{240}{Georgian (Mkhedruli)}{LR}{}% +\TrackLangScriptMap{Glag}{225}{Glagolitic}{LR}{}% +\TrackLangScriptMap{Goth}{206}{Gothic}{LR}{}% +\TrackLangScriptMap{Gran}{343}{Grantha}{LR}{}% +\TrackLangScriptMap{Grek}{200}{Greek}{LR}{}% +\TrackLangScriptMap{Gujr}{320}{Gujarati}{LR}{}% +\TrackLangScriptMap{Guru}{310}{Gurmukhi}{LR}{}% +\TrackLangScriptMap{Hanb}{503}{Han with Bopomofo (alias for Han + Bopomofo)}{LR}{}% +\TrackLangScriptMap{Hang}{286}{Hangul}{LR}{}% +\TrackLangScriptMap{Hani}{500}{Han (Hanzi, Kanji, Hanja)}{LR}{}% +\TrackLangScriptMap{Hano}{371}{Hanunoo}{LR}{}% +\TrackLangScriptMap{Hans}{501}{Han (Simplified variant)}{varies}{}% +\TrackLangScriptMap{Hant}{502}{Han (Traditional variant)}{varies}{}% +\TrackLangScriptMap{Hatr}{127}{Hatran}{RL}{}% +\TrackLangScriptMap{Hebr}{125}{Hebrew}{RL}{}% +\TrackLangScriptMap{Hira}{410}{Hiragana}{LR}{}% +\TrackLangScriptMap{Hluw}{080}{Anatolian Hieroglyphs (Luwian Hieroglyphs, Hittite Hieroglyphs)}{LR}{}% +\TrackLangScriptMap{Hmng}{450}{Pahawh Hmong}{LR}{}% +\TrackLangScriptMap{Hrkt}{412}{Japanese syllabaries (alias for Hiragana + Katakana)}{varies}{}% +\TrackLangScriptMap{Hung}{176}{Old Hungarian (Hungarian Runic)}{RL}{}% +\TrackLangScriptMap{Inds}{610}{Indus (Harappan)}{RL}{}% +\TrackLangScriptMap{Ital}{210}{Old Italic (Etruscan, Oscan, etc.)}{LR}{}% +\TrackLangScriptMap{Jamo}{284}{Jamo (alias for Jamo subset of Hangul)}{LR}{}% +\TrackLangScriptMap{Java}{361}{Javanese}{LR}{}% +\TrackLangScriptMap{Jpan}{413}{Japanese (alias for Han + Hiragana + Katakana)}{varies}{}% +\TrackLangScriptMap{Jurc}{510}{Jurchen}{LR}{}% +\TrackLangScriptMap{Kali}{357}{Kayah Li}{LR}{}% +\TrackLangScriptMap{Kana}{411}{Katakana}{LR}{}% +\TrackLangScriptMap{Khar}{305}{Kharoshthi}{RL}{}% +\TrackLangScriptMap{Khmr}{355}{Khmer}{LR}{}% +\TrackLangScriptMap{Khoj}{322}{Khojki}{LR}{}% +\TrackLangScriptMap{Kitl}{505}{Khitan large script}{LR}{}% +\TrackLangScriptMap{Kits}{288}{Khitan small script}{TB}{}% +\TrackLangScriptMap{Knda}{345}{Kannada}{LR}{}% +\TrackLangScriptMap{Kore}{287}{Korean (alias for Hangul + Han)}{LR}{}% +\TrackLangScriptMap{Kpel}{436}{Kpelle}{LR}{}% +\TrackLangScriptMap{Kthi}{317}{Kaithi}{LR}{}% +\TrackLangScriptMap{Lana}{351}{Tai Tham (Lanna)}{LR}{}% +\TrackLangScriptMap{Laoo}{356}{Lao}{LR}{}% +\TrackLangScriptMap{Latf}{217}{Latin (Fraktur variant)}{varies}{}% +\TrackLangScriptMap{Latg}{216}{Latin (Gaelic variant)}{LR}{}% +\TrackLangScriptMap{Latn}{215}{Latin}{LR}{}% +\TrackLangScriptMap{Leke}{364}{Leke}{LR}{}% +\TrackLangScriptMap{Lepc}{335}{Lepcha}{LR}{}% +\TrackLangScriptMap{Limb}{336}{Limbu}{LR}{}% +\TrackLangScriptMap{Lina}{400}{Linear A}{LR}{}% +\TrackLangScriptMap{Linb}{401}{Linear B}{LR}{}% +\TrackLangScriptMap{Lisu}{399}{Lisu (Fraser)}{LR}{}% +\TrackLangScriptMap{Loma}{437}{Loma}{LR}{}% +\TrackLangScriptMap{Lyci}{202}{Lycian}{LR}{}% +\TrackLangScriptMap{Lydi}{116}{Lydian}{RL}{}% +\TrackLangScriptMap{Mahj}{314}{Mahajani}{LR}{}% +\TrackLangScriptMap{Mand}{140}{Mandaic, Mandaean}{RL}{}% +\TrackLangScriptMap{Mani}{139}{Manichaean}{RL}{}% +\TrackLangScriptMap{Marc}{332}{Marchen}{LR}{}% +\TrackLangScriptMap{Maya}{090}{Mayan hieroglyphs}{varies}{}% +\TrackLangScriptMap{Mend}{438}{Mende Kikakui}{RL}{}% +\TrackLangScriptMap{Merc}{101}{Meroitic Cursive}{RL}{}% +\TrackLangScriptMap{Mero}{100}{Meroitic Hieroglyphs}{RL}{}% +\TrackLangScriptMap{Mlym}{347}{Malayalam}{LR}{}% +\TrackLangScriptMap{Modi}{324}{Modi}{LR}{}% +\TrackLangScriptMap{Mong}{145}{Mongolian}{TB}{}% +\TrackLangScriptMap{Moon}{218}{Moon (Moon code, Moon script, Moon type)}{varies}{}% +\TrackLangScriptMap{Mroo}{199}{Mro, Mru}{LR}{}% +\TrackLangScriptMap{Mtei}{337}{Meitei Mayek (Meithei, Meetei)}{LR}{}% +\TrackLangScriptMap{Mult}{323}{Multani}{LR}{}% +\TrackLangScriptMap{Mymr}{350}{Myanmar (Burmese)}{LR}{}% +\TrackLangScriptMap{Narb}{106}{Old North Arabian (Ancient North Arabian)}{RL}{}% +\TrackLangScriptMap{Nbat}{159}{Nabataean}{RL}{}% +\TrackLangScriptMap{Newa}{333}{Newa, Newar, Newari}{LR}{}% +\TrackLangScriptMap{Nkgb}{420}{Nakhi Geba}{LR}{}% +\TrackLangScriptMap{Nkoo}{165}{N'Ko}{RL}{}% +\TrackLangScriptMap{Nshu}{499}{Nushu}{LR}{}% +\TrackLangScriptMap{Ogam}{212}{Ogham}{varies}{}% +\TrackLangScriptMap{Olck}{261}{Ol Chiki}{LR}{}% +\TrackLangScriptMap{Orkh}{175}{Old Turkic, Orkhon Runic}{RL}{}% +\TrackLangScriptMap{Orya}{327}{Oriya}{LR}{}% +\TrackLangScriptMap{Osge}{219}{Osage}{LR}{}% +\TrackLangScriptMap{Osma}{260}{Osmanya}{LR}{}% +\TrackLangScriptMap{Palm}{126}{Palmyrene}{RL}{}% +\TrackLangScriptMap{Pauc}{263}{Pau Cin Hau}{LR}{}% +\TrackLangScriptMap{Perm}{227}{Old Permic}{LR}{}% +\TrackLangScriptMap{Phag}{331}{Phags-pa}{TB}{}% +\TrackLangScriptMap{Phli}{131}{Inscriptional Pahlavi}{RL}{}% +\TrackLangScriptMap{Phlp}{132}{Psalter Pahlavi}{RL}{}% +\TrackLangScriptMap{Phlv}{133}{Book Pahlavi}{RL}{}% +\TrackLangScriptMap{Phnx}{115}{Phoenician}{RL}{}% +\TrackLangScriptMap{Piqd}{293}{Klingon (KLI plqaD)}{LR}{}% +\TrackLangScriptMap{Plrd}{282}{Miao (Pollard)}{LR}{}% +\TrackLangScriptMap{Prti}{130}{Inscriptional Parthian}{RL}{}% +\TrackLangScriptMap{Qaaa}{900}{Reserved for private use (start)}{varies}{}% +\TrackLangScriptMap{Qaai}{908}{Private use}{varies}{}% +\TrackLangScriptMap{Qabx}{949}{Reserved for private use (end)}{varies}{}% +\TrackLangScriptMap{Rjng}{363}{Rejang (Redjang, Kaganga)}{LR}{}% +\TrackLangScriptMap{Roro}{620}{Rongorongo}{varies}{}% +\TrackLangScriptMap{Runr}{211}{Runic}{LR}{}% +\TrackLangScriptMap{Samr}{123}{Samaritan}{RL}{}% +\TrackLangScriptMap{Sara}{292}{Sarati}{varies}{}% +\TrackLangScriptMap{Sarb}{105}{Old South Arabian}{RL}{}% +\TrackLangScriptMap{Saur}{344}{Saurashtra}{LR}{}% +\TrackLangScriptMap{Sgnw}{095}{SignWriting}{TB}{}% +\TrackLangScriptMap{Shaw}{281}{Shavian (Shaw)}{LR}{}% +\TrackLangScriptMap{Shrd}{319}{Sharada}{LR}{}% +\TrackLangScriptMap{Sidd}{302}{Siddham}{LR}{}% +\TrackLangScriptMap{Sind}{318}{Khudawadi, Sindhi}{LR}{}% +\TrackLangScriptMap{Sinh}{348}{Sinhala}{LR}{}% +\TrackLangScriptMap{Sora}{398}{Sora Sompeng}{LR}{}% +\TrackLangScriptMap{Sund}{362}{Sundanese}{LR}{}% +\TrackLangScriptMap{Sylo}{316}{Syloti Nagri}{LR}{}% +\TrackLangScriptMap{Syrc}{135}{Syriac}{RL}{}% +\TrackLangScriptMap{Syre}{138}{Syriac (Estrangelo variant)}{RL}{}% +\TrackLangScriptMap{Syrj}{137}{Syriac (Western variant)}{RL}{}% +\TrackLangScriptMap{Syrn}{136}{Syriac (Eastern variant)}{RL}{}% +\TrackLangScriptMap{Tagb}{373}{Tagbanwa}{LR}{}% +\TrackLangScriptMap{Takr}{321}{Takri}{LR}{}% +\TrackLangScriptMap{Tale}{353}{Tai Le}{LR}{}% +\TrackLangScriptMap{Talu}{354}{New Tai Lue}{LR}{}% +\TrackLangScriptMap{Taml}{346}{Tamil}{LR}{}% +\TrackLangScriptMap{Taml}{346}{Tamil}{LR}{}% +\TrackLangScriptMap{Tang}{520}{Tangut}{LR}{}% +\TrackLangScriptMap{Tavt}{359}{Tai Viet}{LR}{}% +\TrackLangScriptMap{Telu}{340}{Telugu}{LR}{}% +\TrackLangScriptMap{Teng}{290}{Tengwar}{LR}{}% +\TrackLangScriptMap{Tfng}{120}{Tifinagh (Berber)}{LR}{}% +\TrackLangScriptMap{Tglg}{370}{Tagalog (Baybayin, Alibata)}{LR}{}% +\TrackLangScriptMap{Thaa}{170}{Thaana}{RL}{}% +\TrackLangScriptMap{Thai}{352}{Thai}{LR}{}% +\TrackLangScriptMap{Tibt}{330}{Tibetan}{LR}{}% +\TrackLangScriptMap{Tirh}{326}{Tirhuta}{LR}{}% +\TrackLangScriptMap{Ugar}{040}{Ugaritic}{LR}{}% +\TrackLangScriptMap{Vaii}{470}{Vai}{LR}{}% +\TrackLangScriptMap{Visp}{280}{Visible Speech}{LR}{}% +\TrackLangScriptMap{Wara}{262}{Warang Citi (Varang Kshiti)}{LR}{}% +\TrackLangScriptMap{Wole}{480}{Woleai}{RL}{}% +\TrackLangScriptMap{Xpeo}{030}{Old Persian}{LR}{}% +\TrackLangScriptMap{Xsux}{020}{Cuneiform, Sumero-Akkadian}{LR}{}% +\TrackLangScriptMap{Yiii}{460}{Yi}{LR}{}% +\TrackLangScriptMap{Zinh}{994}{Inherited script}{inherited}{}% +\TrackLangScriptMap{Zmth}{995}{Mathematical notation}{LR}{}% +\TrackLangScriptMap{Zsym}{996}{Symbols}{varies}{}% +\TrackLangScriptMap{Zsye}{993}{Symbols (emoji variant)}{varies}{}% +\TrackLangScriptMap{Zxxx}{997}{Unwritten documents}{varies}{}% +\TrackLangScriptMap{Zyyy}{998}{Undetermined script}{varies}{}% +\TrackLangScriptMap{Zzzz}{999}{Uncoded script}{varies}{}% +% \end{macrocode} +%\changes{1.4}{2019-11-30}{new} +%Load additional script files. +% \begin{macrocode} +\@tracklang@input@extra@script@files % \end{macrocode} % %Restore category code of \texttt{@}. diff --git a/macros/generic/tracklang/tracklang.ins b/macros/generic/tracklang/tracklang.ins index 19adb1e4f4..019b391cd1 100644 --- a/macros/generic/tracklang/tracklang.ins +++ b/macros/generic/tracklang/tracklang.ins @@ -1,4 +1,4 @@ -% tracklang.ins generated using makedtx version 1.2 2019/11/11 16:00 +% tracklang.ins generated using makedtx version 1.2 2019/12/1 17:41 \input docstrip \preamble diff --git a/macros/generic/tracklang/tracklang.pdf b/macros/generic/tracklang/tracklang.pdf Binary files differindex 5aef4affc3..8f0aeee5fc 100644 --- a/macros/generic/tracklang/tracklang.pdf +++ b/macros/generic/tracklang/tracklang.pdf diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/american-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/american-apa6.lbx index c67da1f37c..03e5924d57 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/american-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/american-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{american-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{american-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{american} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.bbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.bbx index 61f99fb3f6..8fff277b41 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.bbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.bbx @@ -1,4 +1,4 @@ -%% Copyright 2019 Philip Kime +p%% Copyright 2019 Philip Kime %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 @@ -12,7 +12,7 @@ %% %% The Current Maintainer of this work is Philip Kime. -\ProvidesFile{apa6.bbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex references style] +\ProvidesFile{apa6.bbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex references style] \RequireBiber[3] \RequireBibliographyStyle{standard} \urlstyle{rm} % APA examples all have URLs in same font as text @@ -251,7 +251,7 @@ \ExecuteBibliographyOptions{% abbreviate=true,% autocite=inline,% - backref=true,% + backref=false,% citetracker=true,% date=apalong,% dateabbrev=false,% @@ -295,18 +295,6 @@ } } -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% It is not APA standard to have backrefs in the bib -% Some users might like it though. - -\newbool{apa:backref} -\DeclareBibliographyOption{apabackref}{% - \ifstrequal{#1}{true} - {\global\booltrue{apa:backref}} - {\global\boolfalse{apa:backref}}} - -% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % (APA 6.29) Additional material sometimes goes in parens @@ -1348,7 +1336,7 @@ \usebibmacro{related}} {}% \usebibmacro{apa:finpunct}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{finentry}} \DeclareBibliographyDriver{newsarticle}{% @@ -1375,7 +1363,7 @@ \usebibmacro{related}} {}% \usebibmacro{apa:finpunct}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{finentry}} \DeclareBibliographyDriver{book}{% @@ -1401,7 +1389,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1428,7 +1416,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1461,7 +1449,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1486,7 +1474,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1517,7 +1505,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1548,7 +1536,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1590,7 +1578,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1621,7 +1609,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1653,7 +1641,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1681,7 +1669,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1710,7 +1698,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1736,7 +1724,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1759,7 +1747,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1786,7 +1774,7 @@ \usebibmacro{doi+eprint+url}% \newunit\newblock \printfield{addendum}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1821,7 +1809,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1850,7 +1838,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1877,7 +1865,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1904,7 +1892,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1933,7 +1921,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1962,7 +1950,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -1989,7 +1977,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -2009,7 +1997,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -2029,7 +2017,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct}% \usebibmacro{finentry}} @@ -2059,7 +2047,7 @@ {\usebibmacro{related:init}% \usebibmacro{related}} {}% - \usebibmacro{apa:pageref}% + \usebibmacro{pageref}% \usebibmacro{apa:finpunct} \usebibmacro{finentry}} @@ -2175,14 +2163,6 @@ % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Wrapper for backrefs - -\newbibmacro{apa:pageref}{% - \ifbool{apa:backref}{\usebibmacro{pageref}}{}} - -% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.cbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.cbx index 8284dff849..581f254693 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.cbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.cbx @@ -9,10 +9,10 @@ %% version 2005/12/01 or later. %% %% This work has the LPPL maintenance status `maintained'. -%% +%% %% The Current Maintainer of this work is Philip Kime. -\ProvidesFile{apa6.cbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex citation style] +\ProvidesFile{apa6.cbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex citation style] \RequireBiber[3] %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -242,7 +242,7 @@ % X and Y and Z (2009) % X and W and V (2010) % -% which have the same namehash due to minnames visibility truncation to 1 +% which have the same namehash due to minnames visibility truncation to 1 % would be printed incorrectly as % \cite{one, two} -> X, Y & Z 2009, 2010 \newbibmacro*{cite}{% @@ -370,7 +370,6 @@ \DeclareDelimFormat[nptextcite]{finalnamedelim} {\ifnum\value{liststop}>2 \finalandcomma\fi\addspace\&\space} -\DeclareMultiCiteCommand{\nptextcites}{\nptextcite}{\multicitedelim} \DeclareCiteCommand{\nptextcite} {\usebibmacro{cite:init}% \usebibmacro{prenote}} @@ -390,7 +389,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % No shorthand -% +% \newbibmacro*{citeyear}{% \iffieldundef{labelyear} {\usebibmacro{cite:init}} @@ -515,8 +514,6 @@ {} {\usebibmacro{postnote}} -\DeclareMultiCiteCommand{\textcites}{\textcite}{\compcitedelim} - \DeclareCiteCommand{\textcite} {\usebibmacro{cite:init}% \usebibmacro{prenote}} @@ -535,4 +532,17 @@ {} {\usebibmacro{postnote}} + +\DeclareMultiCiteCommand{\cites}{\cite}{\setunit{\multicitedelim}} +\DeclareMultiCiteCommand{\textcites}{\textcite}{\setunit{\compcitedelim}} +\DeclareMultiCiteCommand{\nptextcites}{\nptextcite}{\setunit{\multicitedelim}} +\DeclareMultiCiteCommand{\parencites}[\mkbibparens]{\parencite} + {\setunit{\multicitedelim}} +\DeclareMultiCiteCommand{\footcites}[\mkbibfootnote]{\footcite} + {\setunit{\multicitedelim}} +\DeclareMultiCiteCommand{\footcitetexts}[\mkbibfootnotetext] + {\footcitetext}{\setunit{\multicitedelim}} +\DeclareMultiCiteCommand{\smartcites}[\iffootnote\mkbibparens\mkbibfootnote] + {\smartcite}{\setunit{\multicitedelim}} + \endinput diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.dbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.dbx index 48f94999d7..2dbac52698 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.dbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/apa6.dbx @@ -12,7 +12,7 @@ %% %% The Current Maintainer of this work is Philip Kime. -\ProvidesFile{apa6.dbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex style data model] +\ProvidesFile{apa6.dbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex style data model] \RequireBiber[3] \DeclareDatamodelEntrytypes{ diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/austrian-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/austrian-apa6.lbx index 4ca5219127..73cc9eff56 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/austrian-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/austrian-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{austrian-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{austrian-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{austrian} % Following DGPs guidlines for German/Austrian diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa-test.pdf b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa-test.pdf Binary files differdeleted file mode 100644 index 92de9ef490..0000000000 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa-test.pdf +++ /dev/null diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6-test.pdf b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6-test.pdf Binary files differindex 3ae40818e7..08decb866a 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6-test.pdf +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6-test.pdf diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6.pdf b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6.pdf Binary files differindex ae85a92118..52bc6a548c 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6.pdf +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6.pdf diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6.tex b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6.tex index 221bb1c916..e2acfe3544 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6.tex +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/biblatex-apa6.tex @@ -24,7 +24,7 @@ url={http://mirror.ctan.org/macros/latex/exptl/biblatex-contrib/biblatex-apa/}, author={Philip Kime}, email={Philip@kime.org.uk}, - revision={8.1}, + revision={8.2}, date={\today}} \hypersetup{% @@ -251,16 +251,6 @@ The following options are set as usual in the options passed to |biblatex|. \begin{ltxcode} -apabackref=true|false -\end{ltxcode}% | stupid comment to stop emacs highlighting as verb due - % to single pipe - -\noindent It is not APA style to include backreferences in the References to -pages where citations of the entry occur. However, this is very -useful, especially in proofing and so if you set the |apabackref| -option to «true», these are enabled. The default is «false». - -\begin{ltxcode} apamaxprtauth=<num> \end{ltxcode} @@ -467,6 +457,10 @@ applied to the data stream by |biber| and does not change your \file{.bib}. \section{Revision history}\label{rev} \begin{changelog} +\begin{release}{8.2}{2019-12-01} +\item Removed |apabackref| option, use the standard + |biblatex| |backref| option instead +\end{release} \begin{release}{8.1}{2019-11-27} \item Corrected documentation for legacy 6th edition style diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/brazilian-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/brazilian-apa6.lbx index ef292120b2..436ac9c87a 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/brazilian-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/brazilian-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{brazilian-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{brazilian-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{brazilian} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/british-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/british-apa6.lbx index 6a31ce4945..fb681549b7 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/british-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/british-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{british-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{british-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{british} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/danish-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/danish-apa6.lbx index 8e3f35c134..dccb0a4016 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/danish-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/danish-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{danish-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{danish-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{danish} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/dutch-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/dutch-apa6.lbx index e6bd73bc8f..f49dd16eeb 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/dutch-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/dutch-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{dutch-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{dutch-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{dutch} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/english-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/english-apa6.lbx index 2dbc0716e9..a2b4dcbe30 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/english-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/english-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{english-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{english-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{english} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/french-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/french-apa6.lbx index 10a6b16dca..ced24ab438 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/french-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/french-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{french-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{french-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{french} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/galician-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/galician-apa6.lbx index 7430bc6601..0bdac305b2 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/galician-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/galician-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{galician-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{galician-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{galician} \setcounter{smartand}{0} % Turn off "smart and" or ampersands will all be replaced diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/german-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/german-apa6.lbx index 74a58af809..6fa6a51be1 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/german-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/german-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{german-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{german-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{german} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/greek-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/greek-apa6.lbx index 130a5ae1c8..c85fb78e9e 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/greek-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/greek-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{greek-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{greek-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{greek} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/italian-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/italian-apa6.lbx index 10682b6242..deaf12a53d 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/italian-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/italian-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{italian-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{italian-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{italian} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/naustrian-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/naustrian-apa6.lbx index 1885026e67..04633411ae 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/naustrian-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/naustrian-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{naustrian-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{naustrian-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{naustrian} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/ngerman-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/ngerman-apa6.lbx index 8aa8892ddd..e4f82536e0 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/ngerman-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/ngerman-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{ngerman-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{ngerman-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{ngerman} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/norsk-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/norsk-apa6.lbx index 25843dac49..82aede694c 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/norsk-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/norsk-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{norsk-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{norsk-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{norsk} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/norwegian-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/norwegian-apa6.lbx index 58edd9310b..7607c475b5 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/norwegian-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/norwegian-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{norwegian-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{norwegian-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{norwegian} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/nswissgerman-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/nswissgerman-apa6.lbx index a39910cad6..959144cbc0 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/nswissgerman-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/nswissgerman-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{nswissgerman-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{nswissgerman-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{nswissgerman} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/nynorsk-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/nynorsk-apa6.lbx index 6354be0d65..9fa7a8627f 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/nynorsk-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/nynorsk-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{nynorsk-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{nynorsk-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{nynorsk} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/portuguese-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/portuguese-apa6.lbx index 09e7c65896..33b8adf4ac 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/portuguese-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/portuguese-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{portuguese-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{portuguese-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{portuguese} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/russian-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/russian-apa6.lbx index c1d91d306f..bf5c6864e5 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/russian-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/russian-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{russian-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{russian-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{russian} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/slovene-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/slovene-apa6.lbx index 04d3ad581a..a572fa9ce0 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/slovene-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/slovene-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{slovene-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{slovene-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{slovene} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/spanish-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/spanish-apa6.lbx index 431c4e56f1..1dab1f59bb 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/spanish-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/spanish-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{spanish-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{spanish-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{spanish} \setcounter{smartand}{0} % Turn off "smart and" or ampersands will all be replaced diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/swedish-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/swedish-apa6.lbx index bb8c0f8f4e..1e9e68a6bf 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/swedish-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/swedish-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{swedish-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{swedish-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{swedish} % (APA 6.22) The example abbreviations diff --git a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/swissgerman-apa6.lbx b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/swissgerman-apa6.lbx index b8d0f0a0ce..e85e399990 100644 --- a/macros/latex/contrib/biblatex-contrib/biblatex-apa6/swissgerman-apa6.lbx +++ b/macros/latex/contrib/biblatex-contrib/biblatex-apa6/swissgerman-apa6.lbx @@ -1,4 +1,4 @@ -\ProvidesFile{swissgerman-apa6.lbx}[2019/11/27\space v8.1\space APA 6th ed. biblatex localisation] +\ProvidesFile{swissgerman-apa6.lbx}[2019/12/01\space v8.2\space APA 6th ed. biblatex localisation] \InheritBibliographyExtras{swissgerman} % Following DGPs guidlines for German/Austrian/Swiss German diff --git a/macros/latex/contrib/hvqrurl/Changes b/macros/latex/contrib/hvqrurl/Changes index dbf1c990f2..85dfdd189e 100644 --- a/macros/latex/contrib/hvqrurl/Changes +++ b/macros/latex/contrib/hvqrurl/Changes @@ -1,2 +1,3 @@ hvqrurl.sty: -0.01 2019-11-27 - first CTAN version +0.01a 2019-12-01 - fixes to the documentation +0.01 2019-11-27 - first CTAN version diff --git a/macros/latex/contrib/hvqrurl/README b/macros/latex/contrib/hvqrurl/README index 12b48923cb..8de40ba379 100644 --- a/macros/latex/contrib/hvqrurl/README +++ b/macros/latex/contrib/hvqrurl/README @@ -3,8 +3,8 @@ Placing an URL as a QR code into the margin of the text. The package loads by default url, qrcode, marginnote, xcolor, and xkeyval -%% This program can be redistributed and/or modified under the terms -%% of the LaTeX Project Public License Distributed from CTAN archives -%% in directory macros/latex/base/lppl.txt. +This file is distributed under the terms of the LaTeX Project Public +License from CTAN archives in directory macros/latex/base/lppl.txt. +Either version 1.3 or, at your option, any later version. hvoss@tug.org
\ No newline at end of file diff --git a/macros/latex/contrib/hvqrurl/doc/hvqrurl.pdf b/macros/latex/contrib/hvqrurl/doc/hvqrurl.pdf Binary files differindex f1e8eb176c..7a0aa0aa49 100644 --- a/macros/latex/contrib/hvqrurl/doc/hvqrurl.pdf +++ b/macros/latex/contrib/hvqrurl/doc/hvqrurl.pdf diff --git a/macros/latex/contrib/hvqrurl/doc/hvqrurl.tex b/macros/latex/contrib/hvqrurl/doc/hvqrurl.tex index 23196651ec..7125c0d723 100644 --- a/macros/latex/contrib/hvqrurl/doc/hvqrurl.tex +++ b/macros/latex/contrib/hvqrurl/doc/hvqrurl.tex @@ -1,4 +1,4 @@ -%% $Id: hvqrurl.tex 1118 2019-11-29 07:56:18Z herbert $ +%% $Id: hvqrurl.tex 1119 2019-11-30 17:36:28Z herbert $ \listfiles \errorcontextlines=100 \documentclass[twoside,usegeometry]{scrartcl} @@ -37,7 +37,7 @@ \hypersetup{urlcolor=blue, linktocpage, colorlinks=true}% \begin{document} -\title{Package \texttt{hvqrurl}\\Creating a QR-code of an URL in the margin \\ver 0.01} +\title{Package \texttt{hvqrurl}\\Creating a QR-code of an URL in the margin \\\small ver 0.01a} \author{Herbert Voß\thanks{\protect\url{hvoss@tug.org}}} \date{\today} \maketitle @@ -52,13 +52,13 @@ and \end{abstract} -\section{The macro} +\section{The macros} \begin{BDef} -\Lcs{hvqrset}\Largb{key=value list}\\ -\Lcs{hvqrurl}\Largb{key=value list}\Largb{URL}\\ -\Lcs{hvqrurl*}\Largb{key=value list}\Largb{URL} +\Lcs{hvqrset}\Largb{key=value, \ldots}\\ +\Lcs{hvqrurl}\OptArg{key=value, \ldots}\Largb{URL}\\ +\Lcs{hvqrurl*}\OptArg{key=value, \ldots}\Largb{URL} \end{BDef} With the default macro \Lcs{hvqrurl} the URL is printed as as QR code into the margin and @@ -66,6 +66,13 @@ in the the text as usual with the macro \Lcs{url}, for example \hvqrurl{https:// With \LPack{hyperref} you'll get the the same color for the QR code as for the URL link and, of course, is also a link. This example shows the default setting for a QR code. +With \Lcs{hvqrset} one can set the optional arguments globally. For example if one do not want all +QR codes not as a link when using \LPack{hyperref}: + +\begin{lstlisting} +\hvqrset{qrlink=nolink} +\end{lstlisting} + \section{Optional arguments} @@ -75,7 +82,6 @@ is also a link. This example shows the default setting for a QR code. With \Lkeyset{qrlink=nolink} the QR code is no link: \hvqrurl[qrlink=nolink]{https://mirror.ctan.org/pkg/hvqrurl}. The default setting is \Lkeyset{qrlink=link}. \end{lstlisting} - With \Lkeyset{qrlink=nolink} the QR code is no link: \hvqrurl[qrlink=nolink]{https://mirror.ctan.org/pkg/hvqrurl}. The default setting is \Lkeyset{qrlink=link}. Without using \LPack{hyperref} this optional argument has no meaning. diff --git a/macros/latex/contrib/hvqrurl/latex/hvqrurl.sty b/macros/latex/contrib/hvqrurl/latex/hvqrurl.sty index b8c657b82f..bf27b32006 100644 --- a/macros/latex/contrib/hvqrurl/latex/hvqrurl.sty +++ b/macros/latex/contrib/hvqrurl/latex/hvqrurl.sty @@ -7,7 +7,7 @@ % Copyright 2019 Herbert Voss hvoss@tug.org %% \ProvidesPackage{hvqrurl}[% - 2019/11/27 v.0.01 (Herbert Voss) Supports qr images into the margin (hv)] + 2019/12/01 v.0.01a (Herbert Voss) Supports qr images into the margin (hv)] % \NeedsTeXFormat{LaTeX2e} \RequirePackage{url} diff --git a/macros/luatex/generic/barracuda/INSTALL.txt b/macros/luatex/generic/barracuda/INSTALL.txt new file mode 100644 index 0000000000..55ce68da5c --- /dev/null +++ b/macros/luatex/generic/barracuda/INSTALL.txt @@ -0,0 +1,30 @@ +Installation +------------ + +Installing `barracuda` for TeX Live + +If you have TeX Live installed from CTAN or from DVD TeX Collection, check +before any modification to your system if the package is already installed +looking for `installed` key in the output of the command: + +$ tlmgr show barracuda + +If `barracuda` is not present, run the command: + +$ tlmgr install barracuda + +If you have installed TeX Live via Linux OS repository try your distribution's +package management system. + +It's also possible a manual installation: + +a. Grab the sources from CTAN or https://github.com/robitex/barracuda . +b. Unzip it at the root of one or your TDS trees. +c. You may need to update some filename database after this, see your TeX + distribution's manual for details. + +Installing for Lua + +Manually copy `src` folder content to a suitable directory of your system that +is reachable to Lua interpreter. + diff --git a/macros/luatex/generic/barracuda/LICENSE.txt b/macros/luatex/generic/barracuda/LICENSE.txt new file mode 100644 index 0000000000..d1d6cd4ea1 --- /dev/null +++ b/macros/luatex/generic/barracuda/LICENSE.txt @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/macros/luatex/generic/barracuda/README.md b/macros/luatex/generic/barracuda/README.md new file mode 100644 index 0000000000..e4ca271287 --- /dev/null +++ b/macros/luatex/generic/barracuda/README.md @@ -0,0 +1,77 @@ +# `barracuda` project + +This Lua library is for drawing barcode symbols. The project delivers modules +to typeset barcode from within a LuaTeX document. Therefore is also possible +to use `barracuda` with a Lua standalone interpreter to draw barcodes with +different graphic format such as `SVG`. +The package does not have dependences. + +![a SVG formatted Code39 symbol](/test/test-ga-svg/test-code39.svg) + +Internal modules is structured to ensure good performance and to allow a +complete user control over barcode symbol parameters :thumbsup: . + +Although development is in beta stage, `barracuda` has a good level of +stability. + +## Barcode symbologies + +So far, are supported + +- Code 39 +- Code 128 +- Interleaved 2 of 5 +- EAN family (EAN8, EAN13, and the add-ons EAN5 and EAN2) + +Other 1D encoding format will be added to the project, then it will be the +turn for 2D barcode type. + +## A very simple LaTeX example + +The LaTeX package `barracuda.sty` under the cover uses Lua code so you need to +compile your source files with LuaTeX or LuajitTeX with the LaTeX format. + +For instance here there is a minimal example for LuaLaTeX: + +```latex +% !TeX program = LuaLaTeX +\documentclass{article} +\usepackage{barracuda} +\begin{document} +\barracuda{code39}{123ABC} +\end{document} +``` + +## Documentation + +Details and package reference can be found in the manual delivered in the `doc` +project directory, even if it is very minimal at the moment. + +The directory `test` contains files that can be seen as code examples. + +## Installation + +The `barracuda` package can be used with pure Lua interpreter or from within a +TeX source file for Lua-powered typesetting engine like LuaTeX. In the first +case you can manually copy `src` folder content to a suitable directory of +your system. Otherwise, you can install the package via `tlmgr` for your TeX +Live distribution. + +If you have installed TeX Live with the `full` schema, `barracuda` is just +available and no further action is required because the last package tagged +version is periodically sent to CTAN. + +TeX Live distribution or Lua interpreter executable are available for a very +large number of Operating Systems so it is also for `barracuda`. + +More detailed istruction will come soon. + +## Contribute + +Contributes are welcome in any form and for any topics. + +## License + +Please, for more legal details refer to LICENSE.txt file. + +Copyright (C) 2019 Roberto Giacomelli diff --git a/macros/luatex/generic/barracuda/barracuda.pdf b/macros/luatex/generic/barracuda/barracuda.pdf Binary files differnew file mode 100644 index 0000000000..3554d40a4a --- /dev/null +++ b/macros/luatex/generic/barracuda/barracuda.pdf diff --git a/macros/luatex/generic/barracuda/barracuda.sty b/macros/luatex/generic/barracuda/barracuda.sty new file mode 100644 index 0000000000..7ee6b02104 --- /dev/null +++ b/macros/luatex/generic/barracuda/barracuda.sty @@ -0,0 +1,21 @@ +% +\NeedsTeXFormat{LaTeX2e}[2009/06/27] +\ProvidesPackage{barracuda}[2018/12/30 v0.1 a barcode typesetting package]% + +\newbox\barracudabox +\newcommand\barracuda[2]{\directlua{ + local barracuda = require "barracuda" + local e = [[#1]] + local s = [[#2]] + local enc, err = barracuda:get_barcode_class():new_encoder(e) + assert(enc, err) + local symb, err = enc:from_string(s); assert(symb, err) + local canvas = barracuda:new_canvas() + symb:append_ga(canvas) + local drv = barracuda:get_driver() + drv:ga_to_hbox(canvas, "barracudabox") +}% +\box\barracudabox +} + +\endinput diff --git a/macros/luatex/generic/barracuda/example/001-13-ean-test.pdf b/macros/luatex/generic/barracuda/example/001-13-ean-test.pdf Binary files differnew file mode 100644 index 0000000000..925a8ad8f0 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/001-13-ean-test.pdf diff --git a/macros/luatex/generic/barracuda/example/001-13-ean-test.tex b/macros/luatex/generic/barracuda/example/001-13-ean-test.tex new file mode 100644 index 0000000000..c0a4db3894 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/001-13-ean-test.tex @@ -0,0 +1,220 @@ +% !TeX program = LuaTeX +% Copyright (C) 2019 Roberto Giacomelli + +\newbox\mybox +\nopagenumbers + +EAN encoder test. + +Test 1: one simple barcode EAN13 with default parameter: + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() + +local ean13, err = barcode:new_encoder("ean-13") +assert(not err, err) + +local symbo, err = ean13:from_string("8006194056290") +assert(not err, err) + +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\medskip +Test 2: one simple EAN8 barcode with default parameter: + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() + +local ean8, err = barcode:new_encoder("ean-8") +assert(not err, err) + +local symbo, err = ean8:from_string("96385074") +assert(not err, err) + +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\medskip +Test 3: one simple EAN5 barcode with default parameter: + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local ean5, err = barcode:new_encoder("ean-5") +assert(not err, err) +local symbo, err = ean5:from_string("54495") +assert(not err, err) +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\medskip +Test 4: one simple EAN2 barcode with default parameter: + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local ean2, err = barcode:new_encoder("ean-2") +assert(not err, err) +local symbo, err = ean2:from_string("53") +assert(not err, err) +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\medskip +Test 5: EAN13 + EAN5 barcode with default parameter: + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local ean, err = barcode:new_encoder("ean-13+5"); assert(not err, err) +local n = 123456789012 +local c = ean:checksum(n) +local s = n .. c +local symbo, err = ean:from_string(s.."12345") +assert(not err, err) +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule Test 5\vrule\box\mybox \vrule Test 5\vrule + +\medskip +Test 6: EAN13 + EAN2 barcode with default parameter: + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local ean, err = barcode:new_encoder("ean-13+2"); assert(not err, err) +local n = 123456789012 +local c = ean:checksum(n) +local s = n .. c +local symbo, err = ean:from_string(s.."12") +assert(not err, err) +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule Test 6\vrule\box\mybox \vrule Test 6\vrule + +\medskip +Test 7: EAN8 + EAN5 barcode with default parameter: + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local ean, err = barcode:new_encoder("ean-8+5"); assert(not err, err) +local n = 1234567 +local c = ean:checksum(n) +local s = n .. c +local symbo, err = ean:from_string(s.."12345") +assert(not err, err) +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule Test 7\vrule\box\mybox \vrule Test 7\vrule + +\medskip +Test 8: EAN8 + EAN2 barcode with default parameter: + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local ean, err = barcode:new_encoder("ean-8+2"); assert(not err, err) +local n = 7865431 +local c = ean:checksum(n) +local s = n .. c +local symbo, err = ean:from_string(s.."88") +assert(not err, err) +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule Test 8\vrule\box\mybox \vrule Test 8\vrule + +\medskip +Test 9: draw an EAN13 symbol with a user defined height. + +\smallskip +We will test also the function barcode:enc\_by\_name(bc\_type, name), +reusing encoders generated previuosly. The height parameter remain local +to the object symbol. +\smallskip + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local ean, err = barcode:enc_by_name("ean-13"); assert(not err, err) +local n = 818571884348 +local c = ean:checksum(n) +local s = n .. c +local symbo, err = ean:from_string(s); assert(not err, err) +local ok, err = symbo:set_param("height", tex.sp "5mm"); assert(ok, err) +local canvas = barracuda:new_canvas() +symbo:append_ga(canvas) + +local s2, err = ean:from_uint(8001120972163); assert(not err, err) +s2:append_ga(canvas, tex.sp "45mm", 0) + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule Test 9\vrule\box\mybox \vrule Test 9\vrule + +\medskip +Test 10: draw EAN13 symbols with a user defined height. + +\smallskip +The parameter height is setting up in the encoder so it will be global. +\smallskip + +\directlua{ +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local ean, err = barcode:enc_by_name("ean-13"); assert(not err, err) +local ok, err = ean:set_param("height", tex.sp "5mm"); assert(ok, err) +local n = 758458535897; local c = ean:checksum(n); local s = n .. c +local s1, err = ean:from_string(s); assert(not err, err) +local canvas = barracuda:new_canvas() +s1:append_ga(canvas) +local s2, err = ean:from_uint(8001120972163); assert(not err, err) +s2:append_ga(canvas, tex.sp "40mm", 0) +local s3, err = ean:from_uint(8000570000310); assert(not err, err) +local ok, e = s3:set_param{height = tex.sp "10mm"}; assert(ok, e) +s3:append_ga(canvas, tex.sp "90mm", 0) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule Test 10\vrule\box\mybox \vrule Test 10\vrule + +\medskip +That's all folk! + +\bye + + diff --git a/macros/luatex/generic/barracuda/example/001-code128-test.lua b/macros/luatex/generic/barracuda/example/001-code128-test.lua new file mode 100644 index 0000000000..78645612dc --- /dev/null +++ b/macros/luatex/generic/barracuda/example/001-code128-test.lua @@ -0,0 +1,32 @@ +-- Copyright (C) 2018 Roberto Giacomelli + +local barracuda = require "barracuda" +local barcode = barracuda:get_barcode_class() +local c128, err = barcode:new_encoder("code128") +assert(not err, err) + +print(c128._NAME) +print(c128._VERSION) + +local info = c128:info() +print("encoder name = ", info.name) +print("description = ", info.description) +for k, tp in ipairs(info.param) do + print(k, tp.name, tp.value) +end + +local symb = c128:from_string("123") +print("Symbol char list:") +for _, c in ipairs(symb._code_data) do + print(c) +end + +local canvas = barracuda:new_canvas() + +symb:append_ga(canvas) + +-- driver library +local drv = barracuda:get_driver() +drv:save("svg", canvas, "c128-123") + + diff --git a/macros/luatex/generic/barracuda/example/001-i2of5-test.pdf b/macros/luatex/generic/barracuda/example/001-i2of5-test.pdf Binary files differnew file mode 100644 index 0000000000..c46bb12d50 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/001-i2of5-test.pdf diff --git a/macros/luatex/generic/barracuda/example/001-i2of5-test.tex b/macros/luatex/generic/barracuda/example/001-i2of5-test.tex new file mode 100644 index 0000000000..43c652d66a --- /dev/null +++ b/macros/luatex/generic/barracuda/example/001-i2of5-test.tex @@ -0,0 +1,187 @@ +% !TeX program = LuaTeX +% Copyright (C) 2019 Roberto Giacomelli + +\newbox\mybox +\nopagenumbers + +\directlua{barracuda = require "barracuda"} + +Interleaved 2 of 5 encoder test. + +Test 1: one simple barcode with default parameters: + +\directlua{ +local barcode = barracuda:get_barcode_class() + +local enc, err = barcode:new_encoder("i2of5"); assert(not err, err) +local symbo, err = enc:from_uint(54654681); assert(not err, err) +local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\bigskip +Test 2: one simple barcode with default parameter: + +\directlua{ +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +local symbo, err = enc:from_uint(1234567895); assert(not err, err) +local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +% check digit tests + +\directlua{% verify check digits, the last one +local code = { + 7352621, + 9624764, + 7592881, + 5344147, + 742238, + 199766, + 4544739, + 2774794, + 8509895, + 8285157, + 5387564, + 5534371, + 2155678, + 4529545, + 4689164, + 1674910, + 5317837, + 4117698, +} +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +for _, n in ipairs(code) do + local smbl, err = enc:from_uint(n, {check_digit_policy="verify"}) + assert(not err, err) +end +} + +\directlua{% check digits evaluation +local code = { + ["735262"] = 1, + ["962476"] = 4, + ["759288"] = 1, + ["534414"] = 7, + ["74223"] = 8, + ["19976"] = 6, + ["454473"] = 9, + ["277479"] = 4, + ["850989"] = 5, + ["828515"] = 7, + ["538756"] = 4, + ["553437"] = 1, + ["215567"] = 8, + ["452954"] = 5, + ["468916"] = 4, + ["167491"] = 0, + ["531783"] = 7, + ["411769"] = 8, +} +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +for sc, ck in pairs(code) do + local n = tonumber(sc) + local c, err = enc:get_checkdigit(n) + assert(not err, err) + assert(c == ck, "Wrong check digit "..c.." vs "..ck .." for "..sc) +end +} + +\bigskip +Test 3: one simple barcode with check digit automatically added: + +\directlua{ +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +local symbo, err = enc:from_uint(454473, {check_digit_policy="add"}) +assert(not err, err) +local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\bigskip +Test 4: a second simple barcode with check digit automatically added: + +\directlua{ +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +local symbo, err = enc:from_uint(74223, {check_digit_policy="add"}) +assert(not err, err) +local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\bigskip +Test 5: a symbol with native check digits: + +\directlua{ +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +local symbo, err = enc:from_uint(121891259, {check_digit_policy="verify"}) +assert(not err, err) +local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\bigskip +Test 6: bearer bars please: + +\directlua{ +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +local symbo, err = enc:from_uint(747867239, {bearer_bars_enabled = true}) +assert(not err, err) +local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\bigskip +Test 7: bearer bars all around the symbol: + +\directlua{ +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +local symbo, err = enc:from_uint(986790868, {bearer_bars_enabled = true, bearer_bars_layout="frame"}) +assert(not err, err) +local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +\bigskip +Test 8: bearer bars all around the symbol (with string costructor): + +\directlua{ +local barcode = barracuda:get_barcode_class() +local enc, err = barcode:enc_by_name("i2of5"); assert(not err, err) +local symbo, err = enc:from_string("986790868", {bearer_bars_enabled = true, bearer_bars_layout="frame"}) +assert(not err, err) +local canvas = barracuda:new_canvas(); symbo:append_ga(canvas) +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\vrule A\vrule\box\mybox \vrule A\vrule + +That's all folks! + +\bye + + diff --git a/macros/luatex/generic/barracuda/example/003-code39-test.pdf b/macros/luatex/generic/barracuda/example/003-code39-test.pdf Binary files differnew file mode 100644 index 0000000000..4625a40010 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/003-code39-test.pdf diff --git a/macros/luatex/generic/barracuda/example/003-code39-test.tex b/macros/luatex/generic/barracuda/example/003-code39-test.tex new file mode 100644 index 0000000000..a4ba3d6e81 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/003-code39-test.tex @@ -0,0 +1,53 @@ +% !TeX program = LuaTeX +% Copyright (C) 2019 Roberto Giacomelli + +\newbox\mybox +\nopagenumbers + +Test 3: the same Code 39 symbol drawing multiple time on the same canvas + +\directlua{ +local barracuda = require "barracuda" +local c39, err = barracuda:get_barcode_class() + :new_encoder("code39") +assert(not err, err) +local err +local symbol +symbol, err = c39:from_string("ABCDEF12QJ31+") +assert(not err, err) + +local ok, err = c39:set_param("text_vpos", "top") +assert(ok, err) + +local canvas = barracuda:new_canvas() +symbol:append_ga(canvas) + +local ok, err = symbol:set_param("text_hpos", "center") +assert(ok, err) +symbol:append_ga(canvas, tex.sp "4.5cm") + +local ok, err = symbol:set_param("text_hpos", "right") +assert(ok, err) +symbol:append_ga(canvas, tex.sp "9.0cm") + +local ok, err = c39:set_param("text_vpos", "bottom") +assert(ok, err) + +local ok, err = symbol:set_param("text_hpos", "left") +symbol:append_ga(canvas, 0, tex.sp "-2.0cm") + +local ok, err = symbol:set_param("text_hpos", "center") +assert(ok, err) +symbol:append_ga(canvas, tex.sp "4.5cm", tex.sp "-2.0cm") + +local ok, err = symbol:set_param("text_hpos", "right") +assert(ok, err) +symbol:append_ga(canvas, tex.sp "9.0cm", tex.sp "-2.0cm") + +local drv = barracuda:get_driver() +drv:ga_to_hbox(canvas, "mybox") +} +\box\mybox +\bye + + diff --git a/macros/luatex/generic/barracuda/example/003-ean-test.pdf b/macros/luatex/generic/barracuda/example/003-ean-test.pdf Binary files differnew file mode 100644 index 0000000000..e03c2d48d7 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/003-ean-test.pdf diff --git a/macros/luatex/generic/barracuda/example/003-ean-test.tex b/macros/luatex/generic/barracuda/example/003-ean-test.tex new file mode 100644 index 0000000000..59b17c4c07 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/003-ean-test.tex @@ -0,0 +1,16 @@ +% !TeX program = LuaLaTeX +\documentclass{standalone} +\usepackage{fontspec} +\setmainfont{ocrb10.otf} +\newbox\mybox +\directlua{ + local barracuda = require "barracuda" + barracuda:hbox("ean-13", "8006194056290", "mybox") +} + +\begin{document} +\box\mybox +\end{document} + + + diff --git a/macros/luatex/generic/barracuda/example/004-ean-test.lua b/macros/luatex/generic/barracuda/example/004-ean-test.lua new file mode 100644 index 0000000000..017e0725b8 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/004-ean-test.lua @@ -0,0 +1,9 @@ + +local barracuda = require "barracuda" +barracuda:save("ean-13", "8006194056290", "8006194056290") + + + + + + diff --git a/macros/luatex/generic/barracuda/example/006-code39-test.lua b/macros/luatex/generic/barracuda/example/006-code39-test.lua new file mode 100644 index 0000000000..d33ad4ffaf --- /dev/null +++ b/macros/luatex/generic/barracuda/example/006-code39-test.lua @@ -0,0 +1,45 @@ + +local cm = 1864679.8110236 -- sp + +local barracuda = require "barracuda" +local c39, err = barracuda:get_barcode_class() + :new_encoder("code39") +assert(not err, err) +local err +local symbol +symbol, err = c39:from_string("ABCDEF12QJ31+") +assert(not err, err) + +local ok, err = c39:set_param("text_vpos", "top") +assert(ok, err) + +local canvas = barracuda:new_canvas() +symbol:append_ga(canvas) + +local ok, err = symbol:set_param("text_hpos", "center") +assert(ok, err) +symbol:append_ga(canvas, 4.5*cm) + +local ok, err = symbol:set_param("text_hpos", "right") +assert(ok, err) +symbol:append_ga(canvas, 9.0*cm) + +local ok, err = c39:set_param("text_vpos", "bottom") +assert(ok, err) + +local ok, err = symbol:set_param("text_hpos", "left") +symbol:append_ga(canvas, 0, -2.0*cm) + +local ok, err = symbol:set_param("text_hpos", "center") +assert(ok, err) +symbol:append_ga(canvas, 4.5*cm, -2.0*cm) + +local ok, err = symbol:set_param("text_hpos", "right") +assert(ok, err) +symbol:append_ga(canvas, 9.0*cm, -2.0*cm) + +local drv = barracuda:get_driver() +drv:save("svg", canvas, "006-six") + + + diff --git a/macros/luatex/generic/barracuda/example/006-six.svg b/macros/luatex/generic/barracuda/example/006-six.svg new file mode 100644 index 0000000000..25ce8bb34c --- /dev/null +++ b/macros/luatex/generic/barracuda/example/006-six.svg @@ -0,0 +1,653 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Barracuda package (https://github.com/robitex/barracuda) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="132.036779mm" height="33.746381mm" + viewBox="-2.539987 -10.873169 132.036779 33.746381" +> + <g stroke="black"> + <path d="M0.095249 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M0.666746 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M1.142994 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M1.714491 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M2.190738 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M2.666986 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M3.143233 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M3.524231 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M4.095728 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M4.571976 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M5.048223 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M5.524471 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M6.000718 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M6.572215 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M7.048463 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M7.619960 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M8.191457 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M8.667704 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M9.239201 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M9.620199 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M10.001197 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M10.382195 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M10.858443 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M11.525189 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M12.001437 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M12.572934 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M13.049181 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M13.525429 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M14.192175 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M14.573173 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M14.954171 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M15.430419 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M16.001916 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M16.668662 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M17.049660 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M17.525908 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M18.002155 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M18.573652 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M18.954650 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M19.430898 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M19.907145 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M20.383393 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M21.050139 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M21.431137 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M21.907385 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M22.383632 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M22.764630 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M23.145628 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M23.621876 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M24.383872 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M24.860119 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M25.241117 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M25.717365 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M26.479361 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M26.955608 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M27.431856 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M28.003353 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M28.670099 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M29.051097 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M29.432095 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M29.908343 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M30.384590 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M30.956087 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M31.337085 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M31.813333 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M32.289580 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M32.861077 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M33.242075 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M33.813572 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M34.385069 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M34.766067 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M35.337564 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M35.813812 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M36.385309 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M36.861556 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <text x="0.000000" y="-8.773169" font-family="Verdana" font-size="2.877000"> + ABCDEF12QJ31+ </text> + <g stroke="black"> + <path d="M45.095249 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M45.666746 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M46.142994 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M46.714491 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M47.190738 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M47.666986 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M48.143233 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M48.524231 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M49.095728 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M49.571976 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M50.048223 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M50.524471 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M51.000718 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M51.572215 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M52.048463 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M52.619960 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M53.191457 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M53.667704 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M54.239201 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M54.620199 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M55.001197 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M55.382195 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M55.858443 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M56.525189 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M57.001437 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M57.572934 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M58.049181 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M58.525429 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M59.192175 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M59.573173 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M59.954171 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M60.430419 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M61.001916 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M61.668662 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M62.049660 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M62.525908 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M63.002155 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M63.573652 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M63.954650 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M64.430898 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M64.907145 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M65.383393 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M66.050139 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M66.431137 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M66.907385 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M67.383632 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M67.764630 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M68.145628 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M68.621876 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M69.383872 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M69.860119 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M70.241117 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M70.717365 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M71.479361 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M71.955608 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M72.431856 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M73.003353 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M73.670099 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M74.051097 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M74.432095 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M74.908343 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M75.384590 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M75.956087 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M76.337085 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M76.813333 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M77.289580 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M77.861077 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M78.242075 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M78.813572 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M79.385069 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M79.766067 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M80.337564 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M80.813812 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M81.385309 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M81.861556 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <text x="63.478403" y="-8.773169" font-family="Verdana" font-size="2.877000" text-anchor="middle"> + ABCDEF12QJ31+ </text> + <g stroke="black"> + <path d="M90.095249 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M90.666746 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M91.142994 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M91.714491 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M92.190738 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M92.666986 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M93.143233 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M93.524231 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M94.095728 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M94.571976 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M95.048223 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M95.524471 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M96.000718 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M96.572215 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M97.048463 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M97.619960 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M98.191457 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M98.667704 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M99.239201 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M99.620199 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M100.001197 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M100.382195 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M100.858443 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M101.525189 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M102.001437 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M102.572934 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M103.049181 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M103.525429 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M104.192175 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M104.573173 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M104.954171 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M105.430419 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M106.001916 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M106.668662 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M107.049660 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M107.525908 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M108.002155 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M108.573652 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M108.954650 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M109.430898 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M109.907145 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M110.383393 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M111.050139 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M111.431137 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M111.907385 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M112.383632 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M112.764630 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M113.145628 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M113.621876 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M114.383872 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M114.860119 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M115.241117 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M115.717365 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M116.479361 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M116.955608 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M117.431856 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M118.003353 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M118.670099 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M119.051097 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M119.432095 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M119.908343 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M120.384590 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M120.956087 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M121.337085 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M121.813333 -7.999958V-0.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M122.289580 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M122.861077 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M123.242075 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M123.813572 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M124.385069 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M124.766067 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M125.337564 -7.999958V-0.000000" style="stroke-width:0.190499"/> + <path d="M125.813812 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M126.385309 -7.999958V-0.000000" style="stroke-width:0.380998"/> + <path d="M126.861556 -7.999958V-0.000000" style="stroke-width:0.190499"/> + </g> + <text x="126.956806" y="-8.773169" font-family="Verdana" font-size="2.877000" text-anchor="end"> + ABCDEF12QJ31+ </text> + <g stroke="black"> + <path d="M0.095249 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M0.666746 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M1.142994 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M1.714491 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M2.190738 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M2.666986 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M3.143233 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M3.524231 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M4.095728 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M4.571976 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M5.048223 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M5.524471 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M6.000718 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M6.572215 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M7.048463 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M7.619960 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M8.191457 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M8.667704 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M9.239201 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M9.620199 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M10.001197 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M10.382195 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M10.858443 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M11.525189 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M12.001437 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M12.572934 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M13.049181 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M13.525429 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M14.192175 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M14.573173 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M14.954171 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M15.430419 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M16.001916 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M16.668662 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M17.049660 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M17.525908 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M18.002155 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M18.573652 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M18.954650 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M19.430898 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M19.907145 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M20.383393 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M21.050139 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M21.431137 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M21.907385 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M22.383632 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M22.764630 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M23.145628 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M23.621876 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M24.383872 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M24.860119 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M25.241117 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M25.717365 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M26.479361 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M26.955608 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M27.431856 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M28.003353 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M28.670099 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M29.051097 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M29.432095 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M29.908343 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M30.384590 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M30.956087 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M31.337085 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M31.813333 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M32.289580 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M32.861077 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M33.242075 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M33.813572 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M34.385069 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M34.766067 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M35.337564 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M35.813812 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M36.385309 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M36.861556 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <text x="0.000000" y="22.873212" font-family="Verdana" font-size="2.877000"> + ABCDEF12QJ31+ </text> + <g stroke="black"> + <path d="M45.095249 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M45.666746 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M46.142994 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M46.714491 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M47.190738 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M47.666986 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M48.143233 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M48.524231 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M49.095728 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M49.571976 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M50.048223 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M50.524471 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M51.000718 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M51.572215 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M52.048463 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M52.619960 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M53.191457 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M53.667704 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M54.239201 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M54.620199 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M55.001197 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M55.382195 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M55.858443 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M56.525189 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M57.001437 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M57.572934 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M58.049181 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M58.525429 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M59.192175 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M59.573173 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M59.954171 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M60.430419 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M61.001916 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M61.668662 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M62.049660 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M62.525908 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M63.002155 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M63.573652 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M63.954650 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M64.430898 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M64.907145 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M65.383393 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M66.050139 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M66.431137 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M66.907385 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M67.383632 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M67.764630 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M68.145628 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M68.621876 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M69.383872 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M69.860119 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M70.241117 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M70.717365 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M71.479361 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M71.955608 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M72.431856 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M73.003353 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M73.670099 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M74.051097 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M74.432095 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M74.908343 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M75.384590 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M75.956087 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M76.337085 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M76.813333 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M77.289580 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M77.861077 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M78.242075 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M78.813572 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M79.385069 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M79.766067 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M80.337564 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M80.813812 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M81.385309 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M81.861556 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <text x="63.478403" y="22.873212" font-family="Verdana" font-size="2.877000" text-anchor="middle"> + ABCDEF12QJ31+ </text> + <g stroke="black"> + <path d="M90.095249 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M90.666746 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M91.142994 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M91.714491 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M92.190738 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M92.666986 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M93.143233 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M93.524231 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M94.095728 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M94.571976 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M95.048223 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M95.524471 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M96.000718 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M96.572215 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M97.048463 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M97.619960 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M98.191457 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M98.667704 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M99.239201 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M99.620199 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M100.001197 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M100.382195 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M100.858443 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M101.525189 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M102.001437 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M102.572934 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M103.049181 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M103.525429 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M104.192175 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M104.573173 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M104.954171 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M105.430419 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M106.001916 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M106.668662 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M107.049660 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M107.525908 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M108.002155 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M108.573652 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M108.954650 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M109.430898 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M109.907145 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M110.383393 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M111.050139 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M111.431137 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M111.907385 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M112.383632 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M112.764630 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M113.145628 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M113.621876 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M114.383872 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M114.860119 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M115.241117 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M115.717365 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M116.479361 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M116.955608 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M117.431856 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M118.003353 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M118.670099 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M119.051097 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M119.432095 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M119.908343 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M120.384590 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M120.956087 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M121.337085 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M121.813333 12.000042V20.000000" style="stroke-width:0.380998"/> + </g> + <g stroke="black"> + <path d="M122.289580 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M122.861077 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M123.242075 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M123.813572 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M124.385069 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <g stroke="black"> + <path d="M124.766067 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M125.337564 12.000042V20.000000" style="stroke-width:0.190499"/> + <path d="M125.813812 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M126.385309 12.000042V20.000000" style="stroke-width:0.380998"/> + <path d="M126.861556 12.000042V20.000000" style="stroke-width:0.190499"/> + </g> + <text x="126.956806" y="22.873212" font-family="Verdana" font-size="2.877000" text-anchor="end"> + ABCDEF12QJ31+ </text> +</svg> + diff --git a/macros/luatex/generic/barracuda/example/01-latex-code39.pdf b/macros/luatex/generic/barracuda/example/01-latex-code39.pdf Binary files differnew file mode 100644 index 0000000000..d40c55f46c --- /dev/null +++ b/macros/luatex/generic/barracuda/example/01-latex-code39.pdf diff --git a/macros/luatex/generic/barracuda/example/01-latex-code39.tex b/macros/luatex/generic/barracuda/example/01-latex-code39.tex new file mode 100644 index 0000000000..c74935ed8d --- /dev/null +++ b/macros/luatex/generic/barracuda/example/01-latex-code39.tex @@ -0,0 +1,14 @@ +% !TeX program = LuaLaTeX +% Copyright (C) 2019 Roberto Giacomelli + +\documentclass{article} + +\usepackage{barracuda} + +\begin{document} + +A\barracuda{code39}{123QWE}A + +\end{document} + + diff --git a/macros/luatex/generic/barracuda/example/8006194056290.svg b/macros/luatex/generic/barracuda/example/8006194056290.svg new file mode 100644 index 0000000000..f7965e94d4 --- /dev/null +++ b/macros/luatex/generic/barracuda/example/8006194056290.svg @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Barracuda package (https://github.com/robitex/barracuda) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="37.289804mm" height="25.279878mm" + viewBox="-3.629981 -24.499871 37.289804 25.279878" +> + <g stroke="black"> + <path d="M0.164999 -24.499871V-0.000000" style="stroke-width:0.329998"/> + <path d="M0.824996 -24.499871V-0.000000" style="stroke-width:0.329998"/> + </g> + <g stroke="black"> + <path d="M2.309988 -24.499871V-1.649991" style="stroke-width:0.659997"/> + <path d="M3.134984 -24.499871V-1.649991" style="stroke-width:0.329998"/> + </g> + <g stroke="black"> + <path d="M3.794980 -24.499871V-1.649991" style="stroke-width:0.329998"/> + <path d="M5.114973 -24.499871V-1.649991" style="stroke-width:0.989995"/> + </g> + <g stroke="black"> + <path d="M6.104968 -24.499871V-1.649991" style="stroke-width:0.329998"/> + <path d="M7.259962 -24.499871V-1.649991" style="stroke-width:1.319993"/> + </g> + <g stroke="black"> + <path d="M8.579955 -24.499871V-1.649991" style="stroke-width:0.659997"/> + <path d="M9.899948 -24.499871V-1.649991" style="stroke-width:0.659997"/> + </g> + <g stroke="black"> + <path d="M11.054942 -24.499871V-1.649991" style="stroke-width:0.329998"/> + <path d="M12.044937 -24.499871V-1.649991" style="stroke-width:0.989995"/> + </g> + <g stroke="black"> + <path d="M13.034931 -24.499871V-1.649991" style="stroke-width:0.329998"/> + <path d="M14.519924 -24.499871V-1.649991" style="stroke-width:0.659997"/> + </g> + <g stroke="black"> + <path d="M15.344919 -24.499871V-0.000000" style="stroke-width:0.329998"/> + <path d="M16.004916 -24.499871V-0.000000" style="stroke-width:0.329998"/> + </g> + <g stroke="black"> + <path d="M16.994911 -24.499871V-1.649991" style="stroke-width:0.989995"/> + <path d="M18.314904 -24.499871V-1.649991" style="stroke-width:0.329998"/> + </g> + <g stroke="black"> + <path d="M18.974900 -24.499871V-1.649991" style="stroke-width:0.329998"/> + <path d="M20.294893 -24.499871V-1.649991" style="stroke-width:0.989995"/> + </g> + <g stroke="black"> + <path d="M21.284888 -24.499871V-1.649991" style="stroke-width:0.329998"/> + <path d="M21.944885 -24.499871V-1.649991" style="stroke-width:0.329998"/> + </g> + <g stroke="black"> + <path d="M23.759875 -24.499871V-1.649991" style="stroke-width:0.659997"/> + <path d="M24.749870 -24.499871V-1.649991" style="stroke-width:0.659997"/> + </g> + <g stroke="black"> + <path d="M26.234862 -24.499871V-1.649991" style="stroke-width:0.989995"/> + <path d="M27.224857 -24.499871V-1.649991" style="stroke-width:0.329998"/> + </g> + <g stroke="black"> + <path d="M28.544850 -24.499871V-1.649991" style="stroke-width:0.989995"/> + <path d="M29.864843 -24.499871V-1.649991" style="stroke-width:0.329998"/> + </g> + <g stroke="black"> + <path d="M30.524839 -24.499871V-0.000000" style="stroke-width:0.329998"/> + <path d="M31.184836 -24.499871V-0.000000" style="stroke-width:0.329998"/> + </g> + <text x="-3.629981" y="0.780007" font-family="Verdana" font-size="2.877000"> + 8 </text> + <text y="0.780007" font-family="Verdana" font-size="2.877000" text-anchor="middle"> + <tspan x="2.043326">0</tspan> + <tspan x="4.459979">0</tspan> + <tspan x="6.876631">6</tspan> + <tspan x="9.293284">1</tspan> + <tspan x="11.709936">9</tspan> + <tspan x="14.126589">4</tspan> + </text> + <text y="0.780007" font-family="Verdana" font-size="2.877000" text-anchor="middle"> + <tspan x="17.223246">0</tspan> + <tspan x="19.639899">5</tspan> + <tspan x="22.056551">6</tspan> + <tspan x="24.473204">2</tspan> + <tspan x="26.889856">9</tspan> + <tspan x="29.306509">0</tspan> + </text> +</svg> + diff --git a/macros/luatex/generic/barracuda/example/c128-123.svg b/macros/luatex/generic/barracuda/example/c128-123.svg new file mode 100644 index 0000000000..9f5b5847aa --- /dev/null +++ b/macros/luatex/generic/barracuda/example/c128-123.svg @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Barracuda package (https://github.com/robitex/barracuda) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="18.479903mm" height="9.999947mm" + viewBox="-2.099989 -9.999947 18.479903 9.999947" +> + <g stroke="black"> + <path d="M0.209999 -9.999947V-0.000000" style="stroke-width:0.419998"/> + <path d="M0.734996 -9.999947V-0.000000" style="stroke-width:0.209999"/> + <path d="M1.364993 -9.999947V-0.000000" style="stroke-width:0.209999"/> + </g> + <g stroke="black"> + <path d="M2.414987 -9.999947V-0.000000" style="stroke-width:0.209999"/> + <path d="M3.254983 -9.999947V-0.000000" style="stroke-width:0.629997"/> + <path d="M4.199978 -9.999947V-0.000000" style="stroke-width:0.419998"/> + </g> + <g stroke="black"> + <path d="M4.829975 -9.999947V-0.000000" style="stroke-width:0.419998"/> + <path d="M5.774970 -9.999947V-0.000000" style="stroke-width:0.629997"/> + <path d="M6.614965 -9.999947V-0.000000" style="stroke-width:0.209999"/> + </g> + <g stroke="black"> + <path d="M7.139962 -9.999947V-0.000000" style="stroke-width:0.419998"/> + <path d="M7.874959 -9.999947V-0.000000" style="stroke-width:0.209999"/> + <path d="M8.504955 -9.999947V-0.000000" style="stroke-width:0.629997"/> + </g> + <g stroke="black"> + <path d="M9.344951 -9.999947V-0.000000" style="stroke-width:0.209999"/> + <path d="M10.289946 -9.999947V-0.000000" style="stroke-width:0.419998"/> + <path d="M11.024942 -9.999947V-0.000000" style="stroke-width:0.209999"/> + </g> + <g stroke="black"> + <path d="M11.759938 -9.999947V-0.000000" style="stroke-width:0.419998"/> + <path d="M12.914932 -9.999947V-0.000000" style="stroke-width:0.629997"/> + <path d="M13.544929 -9.999947V-0.000000" style="stroke-width:0.209999"/> + <path d="M14.069926 -9.999947V-0.000000" style="stroke-width:0.419998"/> + </g> +</svg> + diff --git a/macros/luatex/generic/barracuda/lib/barracuda.lua b/macros/luatex/generic/barracuda/lib/barracuda.lua new file mode 100644 index 0000000000..33e81be24f --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/barracuda.lua @@ -0,0 +1,116 @@ +-- Welcome to the 'barracuda' barcode library +-- +-- Encode a message into a barcode symbol, in Lua or within a LuaTeX source file +-- +-- Copyright (C) 2019 Roberto Giacomelli +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +-- Basic Conventions: +-- fields that start with an undercore are private +-- class name follows the snake case naming convention +-- the 'barracuda' table is the only global object to access every package +-- modules. + +local Barracuda = { + _VERSION = "barracuda v0.0.9", + _NAME = "barracuda", + _DESCRIPTION = "Lua library for barcode printing", + _URL = "https://github.com/robitex/barracuda", + _LICENSE = "GNU GENERAL PUBLIC LICENSE, Version 2, June 1991", +} + +-- essential sub-module loading +Barracuda._libgeo = require "lib-geo.libgeo" -- basic vectorial objects +Barracuda._gacanvas = require "lib-geo.gacanvas" -- ga stream library +Barracuda._barcode = require "lib-barcode.barcode" -- barcode abstract class + +local Barcode = Barracuda._barcode +Barcode._libgeo = Barracuda._libgeo + +-- encoder builder +function Barracuda:get_barcode_class() --> Barcode class object + return self._barcode +end + +-- where we place output driver library +function Barracuda:get_driver() --> Driver object, err + if not self._lib_driver then + self._lib_driver = require "lib-driver.driver" + end + return self._lib_driver +end + +function Barracuda:new_canvas() --> driver + local gacanvas = self._gacanvas + return gacanvas:new() +end + +-- high level barcode functions +-- only default options +-- panic on error + +-- save barcode as a graphic external file +function Barracuda:save(bc_type, data, filename, id_drv) + local barcode = self:get_barcode_class() + local enc, err = barcode:new_encoder(bc_type) + assert(enc, err) + local arg_data = type(data) + local symb + if arg_data == "number" then + local err_data + symb, err_data = enc:from_uint(data) + asser(symb, err_data) + elseif arg_data == "string" then + local err_data + symb, err_data = enc:from_string(data) + assert(symb, err_data) + else + error("[argErr] unsupported 'data' type") + end + local canvas = self:new_canvas() + symb:append_ga(canvas) + local driver = self:get_driver() + id_drv = id_drv or "svg" + local ok, out_err = driver:save(id_drv, canvas, filename) + assert(ok, out_err) +end + +-- this is a only LuaTeX method +function Barracuda:hbox(bc_type, data, box_name) + local barcode = self:get_barcode_class() + local enc, err = barcode:new_encoder(bc_type) + assert(enc, err) + local arg_data = type(data) + local symb + if arg_data == "number" then + local err_data + symb, err_data = enc:from_uint(data) + asser(symb, err_data) + elseif arg_data == "string" then + local err_data + symb, err_data = enc:from_string(data) + assert(symb, err_data) + else + error("[argErr] unsupported 'data' type") + end + local canvas = self:new_canvas() + symb:append_ga(canvas) + local driver = self:get_driver() + local ok, err_hbox = driver:ga_to_hbox(canvas, box_name) + assert(ok, err_hbox) +end + +return Barracuda diff --git a/macros/luatex/generic/barracuda/lib/lib-barcode/barcode.lua b/macros/luatex/generic/barracuda/lib/lib-barcode/barcode.lua new file mode 100644 index 0000000000..ed6204528a --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-barcode/barcode.lua @@ -0,0 +1,544 @@ + +-- Barcode abstract class +-- Copyright (C) 2019 Roberto Giacomelli +-- Please see LICENSE.TXT for any legal information about present software + +local Barcode = { + _VERSION = "Barcode v0.0.5", + _NAME = "Barcode", + _DESCRIPTION = "Barcode abstract class", +} +Barcode.__index = Barcode + +-- barcode_type/submodule name +Barcode._available_enc = {-- keys must be lowercase + code39 = "lib-barcode.code39", + code128 = "lib-barcode.code128", + ean = "lib-barcode.ean", + i2of5 = "lib-barcode.i2of5", -- Interleaved 2 of 5 +} +Barcode._builder_instances = {} -- encoder builder instances repository + +-- common parameters to all the barcode objects +Barcode._super_par_def = {} +local pardef = Barcode._super_par_def + +-- set an Anchor point (ax, ay) relatively to the barcode bounding box +-- without considering any text object +-- ax = 0, ay = 0 is the lower left corner of the symbol +-- ax = 1, ay = 1 is the upper right corner of the symbol +Barcode.ax = 0.0 +pardef.ax = { + default = 0.0, + unit = "sp", -- scaled point + isReserved = false, + order = 1, + fncheck = function (self, ax, _) --> boolean, err + if ax >= 0.0 and ax <= 1.0 then return true, nil end + return false, "[OutOfRange] 'ax' out of [0, 1] interval" + end, +} +Barcode.ay = 0.0 +pardef.ay = { + default = 0.0, + unit = "sp", -- scaled point + isReserved = false, + order = 2, + fncheck = function (self, ay, _) --> boolean, err + if ay >= 0.0 and ay <= 1.0 then return true, nil end + return false, "[OutOfRange] 'ay' out of [0, 1] interval" + end, +} + +-- Barcode.bbox_to_quietzone -- under assessment + +-- Barcode methods + +-- stateless iterator troughtout the ordered parameters collection +local function p_iter(state, i) + i = i + 1 + local t = state[i] + if t then + return i, t + end +end + +-- main iterator on parameter definitions +function Barcode:param_ord_iter() + local state = {} + -- append family parameter + local p2_family = self._par_def -- base family parameters + local fam_len = 0 + if p2_family then + for pname, pdef in pairs(p2_family) do + state[pdef.order] = { + pname = pname, + pdef = pdef, + isSuper = false, + } + fam_len = fam_len + 1 + end + assert(fam_len == #state) + end + -- append the variant parameters + local var_len = 0 + local var = self._variant + if var then -- specific variant parameters + local p2_variant = assert(self._par_def_variant[var]) + for pname, pdef in pairs(p2_variant) do + if state[pname] then + error("[InternalErr] overriding paramenter '"..pname.."'") + end + state[pdef.order + fam_len] = { + pname = pname, + pdef = pdef, + isSuper = false, + } + var_len = var_len + 1 + end + assert(fam_len + var_len == #state) + end + -- append the super class parameter to the iterator state + local p1 = self._super_par_def + local super_len = 0 + for pname, pdef in pairs(p1) do + if state[pname] then + error("[InternalError] overriding paramenter name '"..pname.."'") + end + state[fam_len + var_len + pdef.order] = { + pname = pname, + pdef = pdef, + isSuper = true, + } + super_len = super_len + 1 + end + assert(super_len + fam_len + var_len == #state) + return p_iter, state, 0 +end + +-- encoder costructor +-- Symbology can be a family with many variants. This is represented by the +-- first argument 'bc_type' formatted as <family>-<variant>. +-- in more details: +-- <family id><dash char><variant id> if there are variants +-- <encoder id> if not +-- i.e. when 'bc_type' is the string "ean-13", "ean" is the barcode family and +-- "13" is its variant name. +-- For whose barcodes that do not have variants, 'bc_type' is simply the endoder id +-- such as "code128". +-- 'id_enc' is an optional identifier useful to retrive an encoder reference later +-- 'opt' is an optional table with the user-defined parameters setting up encoders +-- +function Barcode:new_encoder(bc_type, id_enc, opt) --> object, err + -- argument checking + if type(bc_type) ~= "string" then + return nil, "[ArgErr] 'bc_type' is not a string" + end + local pdash = string.find(bc_type, "-") + local family, variant + if pdash then + family = string.sub(bc_type, 1, pdash - 1) + variant = string.sub(bc_type, pdash + 1) + else + family = bc_type + end + local av_enc = self._available_enc + if not av_enc[family] then -- is the barcode type a real module? + return nil, "[Err] barcode type '"..family.."' not found" + end + if id_enc == nil then + id_enc = (variant or "") .. "_noname" + elseif type(id_enc) ~= "string" then + return nil, "[ArgErr] provided 'id_enc' is not a string" + end + if type(opt) == "table" or opt == nil then + opt = opt or {} + else + return nil, "[ArgErr] provided 'opt' is wrong" + end + local tenc = self._builder_instances + local builder; + if tenc[family] then -- is the encoder builder already loaded? + builder = tenc[family] + else -- loading the encoder builder + local mod_path = av_enc[family] + builder = require(mod_path) + tenc[family] = assert(builder, "[InternalErr] module not found!") + builder._enc_instances = {} + end + if builder._enc_instances[id_enc] then + return nil, "[Err] 'id_enc' already present" + end + local enc = {} -- the new encoder + enc.__index = enc + enc._variant = variant + setmetatable(enc, { + __index = function(_, k) + if builder[k] ~= nil then + return builder[k] + end + return self[k] + end + }) + builder._enc_instances[id_enc] = enc + -- param defition + for _, tpar in enc:param_ord_iter() do + local pname = tpar.pname + local pdef = tpar.pdef + local isSuper = tpar.isSuper + local val = opt[pname] -- param = val + if val ~= nil then + local ok, err = pdef:fncheck(val, enc) + if ok then + enc[pname] = val + else -- error! + return nil, err + end + else + -- load the default value of <pname> + local def_val; if pdef.fndefault then + def_val = pdef:fndefault(enc) + else + def_val = pdef.default + end + if not isSuper then + enc[pname] = def_val + end + end + end + if enc.config then -- this must be called after the parameter definition + enc:config(variant) + end + return enc, nil +end + +-- retrive encoder object already created +-- 'name' is optional in case you didn't assign one to the encoder +function Barcode:enc_by_name(bc_type, name) --> <encoder object>, <err> + if type(bc_type) ~= "string" then + return nil, "[ArgErr] 'bc_type' must be a string" + end + local pdash = string.find(bc_type, "-") + local family, variant + if pdash then + family = string.sub(bc_type, 1, pdash - 1) + variant = string.sub(bc_type, pdash + 1) + else + family = bc_type + end + local av_enc = self._available_enc + if not av_enc[family] then -- is the barcode type a real module? + return nil, "[Err] barcode type '"..family.."' not found" + end + local builder = self._builder_instances[family] + if builder == nil then + return nil, "[Err] enc builder '"..family.."' not loaded, use 'new_encoder()' method" + end + if name == nil then + name = (variant or "") .. "_noname" + elseif type(name) ~= "string" then + return nil, "[ArgErr] 'name' must be a string" + end + local repo = builder._enc_instances + local enc = repo[name] + if enc == nil then + return nil, "[Err] encoder '"..name.."' not found" + else + return enc, nil + end +end + +-- base constructors common to all the encoders +-- for numeric only simbology +function Barcode:_check_char(c) --> elem, err + if type(c) ~= "string" or #c ~= 1 then + return nil, "[InternalErr] invalid char" + end + local n = string.byte(c) - 48 + if n < 0 or n > 9 then + return nil, "[ArgErr] found a not digit char" + end + return n, nil +end +function Barcode:_check_digit(n) --> elem, err + if type(n) ~= "number" then + return nil, "[InternalErr] not a number" + end + if n < 0 or n > 9 then + return nil, "[InternalErr] not a digit" + end + return n, nil +end + +-- not empty string --> Barcode object +function Barcode:from_string(symb, opt) --> object, err + assert(self._check_char, "[InternalErr] undefined _check_char() method") + if type(symb) ~= "string" then + return nil, "[ArgErr] 'symb' is not a string" + end + if #symb == 0 then + return nil, "[ArgErr] 'symb' is an empty string" + end + local chars = {} + local len = 0 + for c in string.gmatch(symb, ".") do + local elem, err = self:_check_char(c) + if err then + return nil, err + else + chars[#chars+1] = elem + len = len + 1 + end + end + -- build the barcode object + local o = { + _code_data = chars, -- array of chars + _code_len = len, -- symbol lenght + } + setmetatable(o, self) + if opt ~= nil then + if type(opt) ~= "table" then + return nil, "[ArgErr] 'opt' is not a table" + else + local ok, err = o:set_param(opt) + if not ok then + return nil, err + end + end + end + if o._finalize then + local ok, e = o:_finalize() + if not ok then return nil, e end + end + return o, nil +end + +-- positive integer --> Barcode object +function Barcode:from_uint(n, opt) --> object, err + assert(self._check_digit, "[InternalErr] undefined _check_digit() method") + if type(n) ~= "number" then return nil, "[ArgErr] 'n' is not a number" end + if n < 0 then return nil, "[ArgErr] 'n' must be a positive integer" end + if n - math.floor(n) ~= 0 then + return nil, "[ArgErr] 'n' is not an integer" + end + if opt ~= nil and type(opt) ~= "table" then + return nil, "[ArgErr] 'opt' is not a table" + end + local digits = {} + local i = 0 + if n == 0 then + local elem, err = self:_check_digit(0) + if err then + return nil, err + end + digits[1] = elem + i = 1 + else + while n > 0 do + local d = n % 10 + i = i + 1 + local elem, err = self:_check_digit(d) + if err then + return nil, err + end + digits[i] = elem + n = (n - d) / 10 + end + for k = 1, i/2 do -- reverse the array + local d = digits[k] + local h = i - k + 1 + digits[k] = digits[h] + digits[h] = d + end + end + -- build the barcode object + local o = { + _code_data = digits, -- array of digits + _code_len = i, -- symbol lenght + } + setmetatable(o, self) + if opt ~= nil then + if type(opt) ~= "table" then + return nil, "[ArgErr] 'opt' is not a table" + else + local ok, err = o:set_param(opt) + if not ok then + return nil, err + end + end + end + if o._finalize then + local ok, e = o:_finalize() + if not ok then return nil, e end + end + return o, nil +end + +-- check a parameter set +-- this method check also reserved parameter +-- argments: {k=v, ...}, "default" | "current" +-- if ref is "default" parameters are checked with default values +-- if ref is "current" parameters are checked with current values +function Barcode:check_param(opt, ref) --> boolean, check report + if type(opt) ~= "table" then + return nil, "[ArgErr] opt is not a table" + end + if ref == nil then + ref = "current" + else + if type(ref) ~= "string" then + return nil, "[ArgErr] ref is not a string" + end + if (ref ~= "current") or (ref ~= "default") then + return nil, "[ArgErr] ref can only be 'default' or 'current'" + end + end + -- checking process + local cktab = {} + local isOk = true + local err_rpt -- nil if no error + for _, tpar in self:param_ord_iter() do + local pname = tpar.pname + local pdef = tpar.pdef + -- load the default value of <pname> + local def_val; if pdef.fndefault then + def_val = pdef:fndefault(cktab) + else + def_val = pdef.default + end + local val = opt[pname] + if val ~= nil then + local ok, err = pdef:fncheck(val, cktab) + if ok then + cktab[pname] = val + else -- error! + isOk = false + if err_rpt == nil then err_rpt = {} end + err_rpt[#err_rpt + 1] = { + param = pname, + checked_val = val, + default_val = def_val, + isOk = ok, + err = err, + } + end + end + local v + if ref == "current" then + v = self[pname] + else + v = def_val + end + cktab[pname] = v + end + return isOk, err_rpt +end + +-- restore to the default values all the parameter +-- (reserved parameters are unmodified so no need to restore it) +-- this need further investigation about the conseguence of a restore +-- that reset the parameter but "locally" +-- so this method must be considered experimental +function Barcode:restore_param() --> self :FIXME: + for _, par in ipairs(self._par_id) do + local pdef = self[par.."_def"] + if not pdef.isReserved then + self[par] = pdef.default + end + end + return self +end + +-- create a table with the information of the current barcode encoder +function Barcode:info() --> table + local info = { + name = self._NAME, + version = self._VERSION, + description = self._DESCRIPTION, + param = {}, + } + local tpar = info.param + for _, pardef in self:param_ord_iter() do + local id = pardef.pname + local pdef = pardef.pdef + tpar[#tpar + 1] = { + name = id, + descr = nil, -- TODO: + value = self[id], + isReserved = pdef.isReserved, + unit = pdef.unit, + } + end + return info +end + +-- make accessible by name parameter values +-- id: parameter identifier +function Barcode:get_param(id) --> value, err + if type(id) ~= "string" then + return nil, "[ArgErr] 'id' must be a string" + end + local pardef = self._par_def + if not pardef[id] then + return nil, "[Err] Parameter '"..id.."' doesn't exist" + end + local res = assert(self[id], "[InternalErr] parameter value unreachable") + return res, nil +end + +-- set a barcode parameter only if it is not reserved +-- arguments: +-- :set_param{key = value, key = value, ...} +-- :set_param(key, value) +function Barcode:set_param(arg1, arg2) --> boolean, err + -- processing arguments + local targ + local isPair = true + if type(arg1) == "table" then + if arg2 ~= nil then + return false, "[ArgErr] Further arguments not allowed" + end + targ = arg1 + isPair = false + elseif type(arg1) == "string" then -- key/value + if arg2 == nil then + return false, "[ArgErr] 'value' as the second argument expected" + end + targ = {} + targ[arg1] = arg2 + else + return false, "[ArgErr] param name must be a string" + end + -- preparing to the checking process + local cktab = {} + local ckparam = {} + -- checking process + for _, tpar in self:param_ord_iter() do + local pname = tpar.pname + local pdef = tpar.pdef + local val = targ[pname] -- par = val + if val ~= nil then + if pdef.isReserved then + return false, "[Err] parameter '" .. pname .. + "' is reserved, create another encoder" + end + local ok, err = pdef:fncheck(val, cktab) + if ok then + cktab[pname] = val + ckparam[pname] = val + else -- error! + return false, err + end + else -- no val in user option + cktab[pname] = self[pname] + end + end + for p, v in pairs(ckparam) do + self[p] = v + end + return true, nil +end + +return Barcode + +-- diff --git a/macros/luatex/generic/barracuda/lib/lib-barcode/code128.lua b/macros/luatex/generic/barracuda/lib/lib-barcode/code128.lua new file mode 100644 index 0000000000..317b3de8f8 --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-barcode/code128.lua @@ -0,0 +1,341 @@ +-- Code128 barcode generator module +-- Copyright (C) 2019 Roberto Giacomelli +-- +-- All dimension must be in scaled point (sp) +-- every fields that starts with an undercore sign are intended as private + +local Code128 = { + _VERSION = "code128 v0.0.5", + _NAME = "Code128", + _DESCRIPTION = "Code128 barcode encoder", +} + +Code128._int_def_bar = {-- code bar definitions + [0] = 212222, 222122, 222221, 121223, 121322, 131222, 122213, 122312, + 132212, 221213, 221312, 231212, 112232, 122132, 122231, 113222, 123122, + 123221, 223211, 221132, 221231, 213212, 223112, 312131, 311222, 321122, + 321221, 312212, 322112, 322211, 212123, 212321, 232121, 111323, 131123, + 131321, 112313, 132113, 132311, 211313, 231113, 231311, 112133, 112331, + 132131, 113123, 113321, 133121, 313121, 211331, 231131, 213113, 213311, + 213131, 311123, 311321, 331121, 312113, 312311, 332111, 314111, 221411, + 431111, 111224, 111422, 121124, 121421, 141122, 141221, 112214, 112412, + 122114, 122411, 142112, 142211, 241211, 221114, 413111, 241112, 134111, + 111242, 121142, 121241, 114212, 124112, 124211, 411212, 421112, 421211, + 212141, 214121, 412121, 111143, 111341, 131141, 114113, 114311, 411113, + 411311, 113141, 114131, 311141, 411131, 211412, 211214, 211232, + 2331112, -- this is the stop char at index 106 +} + +Code128._codeset = { + A = 103, -- Start char for Codeset A + B = 104, -- Start char for Codeset B + C = 105, -- Start char for Codeset C + stopChar = 106, -- Stop char + shift = 98, -- A to B or B to A +} + +Code128._switch = { -- codes for switching from a codeset to another one + [103] = {[104] = 100, [105] = 99}, -- from A to B or C + [104] = {[103] = 101, [105] = 99}, -- from B to A or C + [105] = {[103] = 101, [104] = 100}, -- from C to A or B +} + +-- parameters definition +Code128._par_def = {} +local pardef = Code128._par_def + +-- module main parameter +pardef.xdim = { + default = 0.21 * 186467, -- X dimension + unit = "sp", -- scaled point + isReserved = true, + order = 1, -- the one first to be modified + fncheck = function (self, x, _) --> boolean, err + if x >= self.default then + return true, nil + else + return false, "[OutOfRange] too small value for xdim" + end + end, +} + +pardef.ydim = { + default = 10 * 186467, -- Y dimension + unit = "sp", + isReserved = false, + order = 2, + fncheck = function (self, y, tpar) --> boolean, err + local xdim = tpar.xdim + if y >= 10*xdim then + return true, nil + else + return false, "[OutOfRange] too small value for ydim" + end + end, +} + +pardef.quietzone_factor = { + default = 10, + unit = "absolute-number", + isReserved = false, + order = 3, + fncheck = function (self, z, _) --> boolean, err + if z >= 10 then + return true, nil + else + return false, "[OutOfRange] too small value for quietzone_factor" + end + end, +} + +-- create vbar objects +function Code128:config() --> ok, err + -- build Vbar object for the start/stop symbol + local mod = self.xdim + local sc = self._codeset.stopChar -- build the stop char + local n = self._int_def_bar[sc] + local Vbar = self._libgeo.Vbar -- Vbar class + self._vbar = {} + local b = self._vbar + b[sc] = Vbar:from_int(n, mod, true) + return true, nil +end + +-- utility functions + +-- the number of consecutive digits from the index 'i' in the code array +local function count_digits_from(arr, i) + local start = i + local dim = #arr + while i <= dim and (arr[i] > 47 and arr[i] < 58) do + i = i + 1 + end + return i - start +end + +-- evaluate the check digit of the data representation +local function check_digit(code) + local sum = code[1] -- this is the start character + for i = 2, #code do + sum = sum + code[i]*(i-1) + end + return sum % 103 +end + +-- return a pair of boolean the first one is true +-- if a control char and a lower case char occurs in the data +-- and the second one is true if the control char occurs before +-- the lower case char +local function ctrl_or_lowercase(pos, data) --> boolean, boolean|nil + local len = #data + local ctrl_occur, lower_occur = false, false + for i = pos, len do + local c = data[i] + if (not ctrl_occur) and (c >= 0 and c < 32) then + -- [0,31] control chars + if lower_occur then + return true, false -- lowercase char < ctrl char + else + ctrl_occur = true + end + elseif (not lower_occur) and (c > 95 and c < 128) then + -- [96, 127] lower case chars + if ctrl_occur then + return true, true -- ctrl char < lowercase char + else + lower_occur = true + end + end + end + return false -- no such data +end + +-- encode the provided char against a codeset +-- in the future this function will consider FN data +local function encode_char(t, codesetAorB, char_code, codesetA) + local code + if codesetAorB == codesetA then -- codesetA + if char_code < 32 then + code = char_code + 64 + elseif char_code > 31 and char_code < 96 then + code = char_code - 32 + else + error("Not implemented or wrong code") + end + else -- codesetB + if char_code > 31 and char_code < 128 then + code = char_code - 32 + else + error("Not implemented or wrong code") + end + end + t[#t + 1] = code +end + +-- encode the message in a sequence of Code128 symbol minimizing its lenght +local function encode128(arr, codeset, switch) --> data, err :TODO: + local res = {} -- the result array (the check character will be appended) + -- find the Start Character A, B, or C + local cur_codeset + local ndigit = count_digits_from(arr, 1) + local len = #arr + --local no_ctrl_lower_char + if (ndigit == 2 and len == 2) or ndigit > 3 then -- start char code C + cur_codeset = codeset.C + else + local ok, ctrl_first = ctrl_or_lowercase(1, arr) + if ok and ctrl_first then + cur_codeset = codeset.A + else + cur_codeset = codeset.B + end + end + res[#res + 1] = cur_codeset + local pos = 1 -- symbol's index to encode + while pos <= len do + if cur_codeset == codeset.C then + if arr[pos] < 48 or arr[pos] > 57 then -- not numeric char + local ok, ctrl_first = ctrl_or_lowercase(pos, arr) + if ok and ctrl_first then + cur_codeset = codeset.A + else + cur_codeset = codeset.B + end + res[#res + 1] = switch[codeset.C][cur_codeset] + else + local imax = pos + 2*math.floor(ndigit/2) - 1 + for idx = pos, imax, 2 do + res[#res + 1] = (arr[idx] - 48)*10 + arr[idx+1] - 48 + end + pos = pos + imax + ndigit = ndigit - imax + if ndigit == 1 then + -- cur_codeset setup + local ok, ctrl_first = ctrl_or_lowercase(pos + 1, arr) + if ok and ctrl_first then + cur_codeset = codeset.A + else + cur_codeset = codeset.B + end + res[#res + 1] = switch[codeset.C][cur_codeset] + end + end + else --- current codeset is A or B + if ndigit > 3 then + if ndigit % 2 > 1 then -- odd number of digits + encode_char(res, cur_codeset, arr[pos], codeset.A) + pos = pos + 1 + ndigit = ndigit - 1 + end + res[#res + 1] = switch[cur_codeset][codeset.C] + cur_codeset = codeset.C + elseif (cur_codeset == codeset.B) and + (arr[pos] >= 0 and arr[pos] < 32) then -- ops a control char + local ok, ctrl_first = ctrl_or_lowercase(pos + 1, arr) + if ok and (not ctrl_first) then -- shift to codeset A + res[#res + 1] = codeset.shift + encode_char(res, codeset.A, arr[pos], codeset.A) + pos = pos + 1 + ndigit = count_digits_from(pos, arr) + else -- switch to code set A + res[#res + 1] = switch[cur_codeset][codeset.A] + cur_codeset = codeset.A + end + elseif (cur_codeset == codeset.A) and + (arr[pos] > 95 and arr[pos] < 128) then -- ops a lower case char + local ok, ctrl_first = ctrl_or_lowercase(pos+1, arr) + if ok and ctrl_first then -- shift to codeset B + res[#res + 1] = codeset.shift + encode_char(res, codeset.B, arr[pos], codeset.A) + pos = pos + 1 + ndigit = count_digits_from(arr, pos) + else -- switch to code set B + res[#res + 1] = switch[cur_codeset][codeset.B] + cur_codeset = codeset.B + end + else + -- insert char + encode_char(res, cur_codeset, arr[pos], codeset.A) + pos = pos + 1 + ndigit = count_digits_from(arr, pos) + end + end + end + res[#res + 1] = check_digit(res) + res[#res + 1] = codeset.stopChar + return res +end + +-- Code 128 internal functions used by Barcode costructors + +function Code128:_check_char(c) --> elem, err + if type(c) ~= "string" or #c ~= 1 then + return nil, "[InternalErr] invalid char" + end + local b = string.byte(c) + if b > 127 then + local fmt = "[unimplemented] the '%d' is an ASCII extented char" + return nil, string.format(fmt, c) + end + return b, nil +end + +function Code128:_check_digit(n) --> elem, err + if type(n) ~= "number" then + return nil, "[InternalErr] invalid digit" + end + return n + 48, nil +end + +function Code128:_finalize() --> ok, err + local chr = assert(self._code_data, "[InternalErr] '_code_data' field is nil") + local data, err = encode128(chr, self._codeset, self._switch) + if err then return false, err end + -- load dynamically required Vbar objects + local vbar = self._vbar + local oVbar = self._libgeo.Vbar + for _, c in ipairs(data) do + if not vbar[c] then + local n = self._int_def_bar[c] + local mod = self.xdim + vbar[c] = oVbar:from_int(n, mod, true) + end + end + self._enc_data = data + return true, nil +end + +-- Drawing into the provided channel the geometrical barcode data +-- tx, ty is the optional translator vector +-- the function return the canvas reference to allow call chaining +function Code128:append_ga(canvas, tx, ty) --> canvas + local xdim, h = self.xdim, self.ydim + local sw = 11*xdim -- the width of a symbol + local data = self._enc_data + local w = #data * sw + 2 * xdim -- total symbol width + local ax, ay = self.ax, self.ay + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local y1 = y0 + h + local xpos = x0 + -- drawing the symbol + local err + err = canvas:start_bbox_group() + assert(not err, err) + for _, c in ipairs(data) do + local vb = self._vbar[c] + err = canvas:encode_Vbar(vb, xpos, y0, y1) + assert(not err, err) + xpos = xpos + sw + end + -- bounding box setting + local qz = self.quietzone_factor * xdim + -- { xmin, ymin, xmax, ymax } + err = canvas:stop_bbox_group(x0 - qz, y0, x1 + qz, y1) + assert(not err, err) + return canvas +end + +return Code128 +--
\ No newline at end of file diff --git a/macros/luatex/generic/barracuda/lib/lib-barcode/code39.lua b/macros/luatex/generic/barracuda/lib/lib-barcode/code39.lua new file mode 100644 index 0000000000..a639619c63 --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-barcode/code39.lua @@ -0,0 +1,381 @@ +-- Code39 barcode encoder implementation +-- Copyright (C) 2019 Roberto Giacomelli +-- +-- All dimensions must be in scaled point (sp) +-- every fields that starts with an undercore sign are intended as private + +local Code39 = { + _VERSION = "code39 v0.0.5", + _NAME = "Code39", + _DESCRIPTION = "Code39 barcode encoder", +} + +Code39._symb_def = {-- symbol definition + ["0"] = 112122111, ["1"] = 211112112, ["2"] = 211112211, + ["3"] = 111112212, ["4"] = 211122111, ["5"] = 111122112, + ["6"] = 111122211, ["7"] = 212112111, ["8"] = 112112112, + ["9"] = 112112211, ["A"] = 211211112, ["B"] = 211211211, + ["C"] = 111211212, ["D"] = 211221111, ["E"] = 111221112, + ["F"] = 111221211, ["G"] = 212211111, ["H"] = 112211112, + ["I"] = 112211211, ["J"] = 112221111, ["K"] = 221111112, + ["L"] = 221111211, ["M"] = 121111212, ["N"] = 221121111, + ["O"] = 121121112, ["P"] = 121121211, ["Q"] = 222111111, + ["R"] = 122111112, ["S"] = 122111211, ["T"] = 122121111, + ["U"] = 211111122, ["V"] = 211111221, ["W"] = 111111222, + ["X"] = 211121121, ["Y"] = 111121122, ["Z"] = 111121221, + ["-"] = 212111121, ["."] = 112111122, [" "] = 112111221, + ["$"] = 111212121, ["/"] = 121112121, ["+"] = 121211121, + ["%"] = 121212111, +} +Code39._star_def = 112121121 -- '*' start/stop character + +-- parameters definition +Code39._par_def = {} +local pardef = Code39._par_def + +-- module main parameter +pardef.module = { + -- Narrow element X-dimension is the width of the smallest element in a + -- barcode symbol. + -- The X-dimension impacts scan-ability. Within the allowed range, it is + -- recommended to use the largest possible X-dimension that is consistent + -- with label or form design. + -- The module width (width of narrow element) should be at least 7.5 mils + -- or 0.1905mm (a mil is 1/1000 inch). + default = 7.5 * 0.0254 * 186467, -- 7.5 mils (sp) unit misure, + unit = "sp", -- scaled point + isReserved = true, + order = 1, -- the one first to be modified + fncheck = function (self, mod, _) --> boolean, err + if mod >= self.default then return true, nil end + return false, "[OutOfRange] too small value for module" + end, +} + +pardef.ratio = { + -- The "wide" element is a multiple of the "narrow" element and this + -- multiple must remain the same throughout the symbol. This multiple can + -- range between 2.0 and 3.0. Preferred value is 3.0. + -- The multiple for the wide element should be between 2.0 and 3.0 if the + -- narrow element is greater than 20 mils. If the narrow element is less + -- than 20 mils (0.508mm), the multiple can only range between 2.0 and 2.2. + default = 2.0, -- the minimum + unit = "absolute-number", + isReserved = true, + order = 2, + fncheck = function (self, ratio, tparcheck) --> boolean, err + local mils = 0.0254 * 186467 + local mod = tparcheck.module + local maxr; if mod < 20*mils then maxr = 2.2 else maxr = 3.0 end + if ratio < 2.0 then + return false, "[OutOfRange] too small ratio (min 2.0)" + end + if ratio > maxr then + return false, "[OutOfRange] too big ratio (max "..maxr..")" + end + return true, nil + end, +} + +pardef.quietzone = { + -- It is recommended to use the largest possible quiet zone, that is + -- consistent with label or form design. + -- Quiet zones must be at least 10 times the module width or 0.10 inches, + -- whichever is larger. Default value (100 mils) + default = 2.54 * 186467, -- 0.1 inches equal to 100*mils + unit = "sp", -- scaled point + isReserved = false, + order = 3, + fncheck = function (self, qz, tparcheck) --> boolean, err + local mils = 0.0254 * 186467 + local mod = tparcheck.module + local min = math.max(10*mod, 100*mils) + if qz >= min then + return true, nil + end + return false, "[OutOfRange] quietzone too small" + end, + fndefault = function(self, tck) --> default value respect to a set of param + local mod = tck.module + return math.max(10*mod, self.default) + end, +} + +pardef.interspace = { -- Intercharacter gap + -- The intercharacter gap width (igw) is 5.3 times the module width (mw) if + -- mw is less than 10 mils. If mw is 10 mils or greater, the value for igw + -- is 3mw or 53 mils, whichever is greater. However, for quality printers, + -- igw often equals mw. + default = 7.5 * 0.0254 * 186467, -- 1 module, for quality printer + unit = "sp", -- scaled point + isReserved = false, + order = 4, + fncheck = function (self, igw, tparcheck) --> boolean, err + local mod = tparcheck.module + if igw >= mod then return true, nil end + return false, "[OutOfRange] interspace too small" + end, + fndefault = function(self, tck) --> default value respect to a set of param + return tck.module + end, +} + +pardef.height = { + -- To enhance readability, it is recommended that the barcode be designed + -- to be as tall as possible, taking into consideration the aspects of label + -- and forms design. + -- The height should be at least 0.15 times the barcode's length or 0.25 inch. + default = 8 * 186467, -- 8 mm -- TODO: better assessment for symbol length + unit = "sp", -- scaled point + isReserved = false, + order = 5, + fncheck = function (self, h, _) --> boolean, err + local mils = 0.0254 * 186467 + if h >= 250*mils then return true, nil end + return false, "[OutOfRange] height too small" + end, +} + +-- text yes or not +pardef.text_enabled = { -- boolean type + -- enable/disable a text label upon the barcode symbol + default = true, + isReserved = false, + order = 6, + fncheck = function (self, flag, _) --> boolean, err + if type(flag) == "boolean" then + return true, nil + else + return false, "[TypeErr] not a boolean value" + end + end, +} + +-- define the text label vertical position +pardef.text_vpos = { -- enumeration + default = "bottom", + isReserved = false, + order = 7, + policy_enum = { + top = true, -- place text at the top of symbol + bottom = true, -- place text under the symbol + }, + fncheck = function (self, e, _) --> boolean, err + if type(e) ~= "string" then return false, "[TypeError] not a string" end + local keys = self.policy_enum + if keys[e] == true then + return true, nil + else + return false, "[Err] enumeration value '"..e.."' not found" + end + end, +} + +-- define the text label horizontal position +pardef.text_hpos = { -- enumeration + default = "left", + isReserved = false, + order = 8, + policy_enum = { + left = true, + center = true, + right = true, + spaced = true, + }, + fncheck = function (self, e, _) --> boolean, err + if type(e) ~= "string" then return false, "[TypeError] not a string" end + local keys = self.policy_enum + if keys[e] == true then + return true, nil + else + return false, "[Err] enumeration value '"..e.."' not found" + end + end, +} + +-- vertical dimension between symbol and text +pardef.text_gap = { + default = 2.2 * 65536, -- 2.2 pt + isReserved = false, + order = 9, + unit = "em", --> TODO: please put this under further analisys asap + fncheck = function(self, g, _) --> boolean, err + if type(g) == "number" then + if g > 0 then + return true, nil + else + return false, "[OptErr] negative number" + end + else + return false, "[TypeErr] not valid type for gap opt" + end + end, +} + +-- star character appearing +pardef.text_star = { + default = false, + isReserved = false, + order = 10, + fncheck = function(self, flag, _) --> boolean, err + if type(flag) == "boolean" then + return true, nil + else + return false, "[TypeErr] not a boolean value" + end + end, +} + +-- configuration function +function Code39:config() --> ok, err + -- build Vbar object for the start/stop symbol + local mod, ratio = self.module, self.ratio + local n_star = self._star_def + local Vbar = self._libgeo.Vbar -- Vbar class + self._vbar = {['*'] = Vbar:from_int_revpair(n_star, mod, mod*ratio)} + return true, nil +end + +-- overriding Barcode method +function Code39:_check_char(c) --> elem, err + if type(c) ~= "string" or #c ~= 1 then + return nil, "[InternalErr] invalid char" + end + local symb_def = self._symb_def + local n = symb_def[c] + if not n then + local fmt = "[ArgErr] '%s' is not a valid Code 39 symbol" + return nil, string.format(fmt, c) + end + return c, nil +end + +-- overriding Barcode method +function Code39:_check_digit(n) --> elem, err + if type(n) ~= "number" then + return nil, "[InteranlErr] not a number" + end + if n < 0 or n > 9 then + return nil, "[InternalErr] not a digit" + end + return tostring(n), nil +end + +function Code39:_finalize() --> ok, err + local v = assert(self._code_data, "[InternalErr] '_code_data' field is nil") + local vbar = self._vbar + local g_Vbar = self._libgeo.Vbar + local mod, ratio = self.module, self.ratio + local symb_def = self._symb_def + for _, c in ipairs(v) do + if not vbar[c] then + local n1 = symb_def[c] + vbar[c] = g_Vbar:from_int_revpair(n1, mod, mod*ratio) + end + end + return true, nil +end + +-- tx, ty is an optional translator vector +function Code39:append_ga(canvas, tx, ty) --> canvas + local code = self._code_data + local ns = self._code_len -- number of chars inside the symbol + local mod = self.module + local ratio = self.ratio + local interspace = self.interspace + local h = self.height + local xs = mod*(6 + 3*ratio) + local xgap = xs + interspace + local w = xgap*(ns + 1) + xs -- (ns + 2)*xgap - interspace + local ax, ay = self.ax, self.ay + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local y1 = y0 + h + local xpos = x0 + local err + err = canvas:start_bbox_group() + assert(not err, err) + local vbar = self._vbar + -- start/stop symbol + local term_vbar = vbar['*'] + -- draw start symbol + err = canvas:encode_Vbar(term_vbar, xpos, y0, y1) + assert(not err, err) + for _, c in ipairs(code) do -- draw code symbols + xpos = xpos + xgap + local vb = vbar[c] + err = canvas:encode_Vbar(vb, xpos, y0, y1) + assert(not err, err) + end + -- draw stop symbol + err = canvas:encode_Vbar(term_vbar, xpos + xgap, y0, y1) + assert(not err, err) + -- bounding box setting + local qz = self.quietzone + err = canvas:stop_bbox_group(x0 - qz, y0, x1 + qz, y1) + assert(not err, err) + -- check height as the minimum of 15% of length + -- TODO: message could warn the user + -- if 0.15 * w > h then + -- message("The height of the barcode is to small") + -- end + if self.text_enabled then -- human readable text + local chars; if self.text_star then + chars = {"*"} + for _, c in ipairs(code) do + chars[#chars + 1] = c + end + chars[#chars + 1] = "*" + else + chars = {} + for _, c in ipairs(code) do + chars[#chars + 1] = c + end + end + local Text = self._libgeo.Text + local txt = Text:from_chars(chars) + -- setup text position + local txt_vpos = self.text_vpos + local txt_gap = self.text_gap + local ypos, tay; if txt_vpos == "top" then -- vertical setup + ypos = y1 + txt_gap + tay = 0.0 + elseif txt_vpos == "bottom" then + ypos = y0 - txt_gap + tay = 1.0 + else + error("[IntenalErr] text vertical placement option is wrong") + end + local txt_hpos = self.text_hpos + if txt_hpos == "spaced" then -- horizontal setup + local xaxis = x0 + if not self.text_star then + xaxis = xaxis + xgap + end + xaxis = xaxis + xs/2 + err = canvas:encode_Text_xspaced(txt, xaxis, xgap, ypos, tay) + assert(not err, err) + else + local xpos, tax + if txt_hpos == "left" then + xpos = x0 + tax = 0.0 + elseif txt_hpos == "center" then + xpos = (x1 + x0)/2 + tax = 0.5 + elseif txt_hpos == "right" then + xpos = x1 + tax = 1.0 + else + error("[InternalErr] wrong option for text_pos") + end + err = canvas:encode_Text(txt, xpos, ypos, tax, tay) + assert(not err, err) + end + end + return canvas +end + +return Code39 +--
\ No newline at end of file diff --git a/macros/luatex/generic/barracuda/lib/lib-barcode/ean.lua b/macros/luatex/generic/barracuda/lib/lib-barcode/ean.lua new file mode 100644 index 0000000000..6893550a5c --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-barcode/ean.lua @@ -0,0 +1,790 @@ +-- EAN family barcode generator +-- +-- Copyright (C) 2019 Roberto Giacomelli +-- see LICENSE.txt file +-- +-- variant identifiers of the EAN family barcodes: +-- "13" EAN13 +-- "8" EAN8 +-- "5" EAN5 add-on +-- "2" EAN2 add-on +-- "13+5" EAN13 with EAN5 add-on +-- "13+2" EAN13 with EAN2 add-on +-- "8+5" EAN8 with EAN5 add-on +-- "8+2" EAN8 with EAN2 add-on + +local EAN = { + _VERSION = "ean v0.0.5", + _NAME = "ean", + _DESCRIPTION = "EAN barcode encoder", +} + +EAN._codeset_seq = {-- 1 -> A, 2 -> B, 3 -> C +[0]={1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3}, + {1, 1, 2, 1, 2, 2, 3, 3, 3, 3, 3, 3}, + {1, 1, 2, 2, 1, 2, 3, 3, 3, 3, 3, 3}, + {1, 1, 2, 2, 2, 1, 3, 3, 3, 3, 3, 3}, + {1, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}, + {1, 2, 2, 1, 1, 2, 3, 3, 3, 3, 3, 3}, + {1, 2, 2, 2, 1, 1, 3, 3, 3, 3, 3, 3}, + {1, 2, 1, 2, 1, 2, 3, 3, 3, 3, 3, 3}, + {1, 2, 1, 2, 2, 1, 3, 3, 3, 3, 3, 3}, + {1, 2, 2, 1, 2, 1, 3, 3, 3, 3, 3, 3}, +} + +EAN._codeset14_8 = 1 +EAN._codeset58_8 = 3 + +EAN._codeset_5 = { -- check digit => structure +[0]={2, 2, 1, 1, 1}, -- 0 GGLLL + {2, 1, 2, 1, 1}, -- 1 GLGLL + {2, 1, 1, 2, 1}, -- 2 GLLGL + {2, 1, 1, 1, 2}, -- 3 GLLLG + {1, 2, 2, 1, 1}, -- 4 LGGLL + {1, 1, 2, 2, 1}, -- 5 LLGGL + {1, 1, 1, 2, 2}, -- 6 LLLGG + {1, 2, 1, 2, 1}, -- 7 LGLGL + {1, 2, 1, 1, 2}, -- 8 LGLLG + {1, 1, 2, 1, 2}, -- 9 LLGLG +} + +EAN._symbol = { -- codesets A, B, and C + [1] = {[0] = 3211, 2221, 2122, 1411, 1132, 1231, 1114, 1312, 1213, 3112,}, + [2] = {[0] = 1123, 1222, 2212, 1141, 2311, 1321, 4111, 2131, 3121, 2113,}, + [3] = {[0] = 3211, 2221, 2122, 1411, 1132, 1231, 1114, 1312, 1213, 3112,}, +} + +EAN._is_first_bar = {false, false, true} +EAN._start = {111, true} +EAN._stop = {11111, false} + +-- family parameters + +EAN._par_def = {}; local pardef = EAN._par_def + +-- standard module is 0.33 mm but it can vary from 0.264 to 0.66mm +pardef.mod = { + default = 0.33 * 186467, -- (mm to sp) X dimension (original value 0.33) + unit = "sp", -- scaled point + isReserved = true, + order = 1, -- the one first to be modified + fncheck = function (self, x, _) --> boolean, err + local mm = 186467 + local min, max = 0.264 * mm, 0.660 * mm + if x < min then + return false, "[OutOfRange] too small value for mod" + elseif x > max then + return false, "[OutOfRange] too big value for mod" + end + return true, nil + end, +} + +pardef.height = { + default = 22.85 * 186467, -- 22.85 mm + unit = "sp", + isReserved = false, + order = 2, + fncheck = function (self, h, _) --> boolean, err + if h > 0 then + return true, nil + else + return false, "[OutOfRange] non positive value for height" + end + end, +} + +pardef.quietzone_left_factor = { + default = 11, + unit = "absolute-number", + isReserved = false, + order = 3, + fncheck = function (self, qzf, _) --> boolean, err + if qzf > 0 then + return true, nil + else + return false, "[OutOfRange] non positive value for quietzone_left_factor" + end + end, +} + +pardef.quietzone_right_factor = { + default = 7, + unit = "absolute-number", + isReserved = false, + order = 4, + fncheck = function (self, qzf, _) --> boolean, err + if qzf > 0 then + return true, nil + else + return false, "[OutOfRange] non positive value for quietzone_right_factor" + end + end, +} + +pardef.bars_depth_factor = { + default = 5, + unit = "absolute-number", + isReserved = false, + order = 5, + fncheck = function (self, b, _) --> boolean, err + if b >= 0 then + return true, nil + else + return false, "[OutOfRange] non positive value for bars_depth_factor" + end + end, +} + +-- enable/disable a text label upon the barcode symbol +pardef.text_enabled = { -- boolean type + default = true, + isReserved = false, + order = 6, + fncheck = function (self, flag, _) --> boolean, err + if type(flag) == "boolean" then + return true, nil + else + return false, "[TypeErr] not a boolean value for text_enabled" + end + end, +} + +pardef.text_ygap_factor = { + default = 1.0, + unit = "absolute-number", + isReserved = false, + order = 7, + fncheck = function (self, t, _) --> boolean, err + if t >= 0 then + return true, nil + else + return false, "[OutOfRange] non positive value for text_ygap_factor" + end + end, +} + +pardef.text_xgap_factor = { + default = 0.75, + unit = "absolute-number", + isReserved = false, + order = 8, + fncheck = function (self, t, _) --> boolean, err + if t >= 0 then + return true, nil + else + return false, "[OutOfRange] non positive value for text_xgap_factor" + end + end, +} + +-- variant parameters + +EAN._par_def_variant = { + ["13"] = {}, -- EAN13 + ["8"] = {}, -- EAN8 + ["5"] = {}, -- add-on EAN5 + ["2"] = {}, -- add-on EAN2 + ["13+5"] = {}, -- EAN13 with EAN5 add-on + ["13+2"] = {}, -- EAN13 with EAN2 add-on + ["8+5"] = {}, -- EAN8 with EAN5 add-on + ["8+2"] = {}, -- EAN8 with EAN2 add-on +} + +-- ean13_pardef.text_ISBN parameter -- TODO: + +-- EAN 13/8 + add-on parameters +local addon_xgap_factor = {-- distance between symbol + default = 10, + unit = "absolute-number", + isReserved = false, + order = 1, + fncheck = function (self, t, _) --> boolean, err + if t >= 7 then + return true, nil + else + return false, "[OutOfRange] not positive value for xgap_factor" + end + end, +} +EAN._par_def_variant["13+5"].addon_xgap_factor = addon_xgap_factor +EAN._par_def_variant["13+2"].addon_xgap_factor = addon_xgap_factor +EAN._par_def_variant["8+5"].addon_xgap_factor = addon_xgap_factor +EAN._par_def_variant["8+2"].addon_xgap_factor = addon_xgap_factor + +-- configuration functions + +-- utility for generic configuration of full symbol, add-on included +-- n1 length of main symbol, 8 or 13 +-- n2 length of add-on symbol, 2 or 5 +local function config_full(ean, Vbar, mod, n1, n2) + local i1 = tostring(n1) + local fn_1 = assert(ean._config_variant[i1]) + fn_1(ean, Vbar, mod) + local i2 = tostring(n2) + local fn_2 = assert(ean._config_variant[i2]) + fn_2(ean, Vbar, mod) + ean._main_len = n1 + ean._addon_len = n2 + ean._is_last_checksum = true +end + +EAN._config_variant = { + ["13"] = function (ean13, Vbar, mod) + ean13._main_len = 13 + ean13._is_last_checksum = true + local start = ean13._start + local stop = ean13._stop + ean13._13_start_stop_vbar = Vbar:from_int(start[1], mod, start[2]) + ean13._13_ctrl_center_vbar = Vbar:from_int(stop[1], mod, stop[2]) + ean13._13_codeset_vbar = {} + local tvbar = ean13._13_codeset_vbar + for i_cs, codetab in ipairs(ean13._symbol) do + tvbar[i_cs] = {} + local tv = tvbar[i_cs] + local isbar = ean13._is_first_bar[i_cs] + for i = 0, 9 do + tv[i] = Vbar:from_int(codetab[i], mod, isbar) + end + end + end, + ["8"] = function (ean8, Vbar, mod) + ean8._main_len = 8 + ean8._is_last_checksum = true + local start = ean8._start + local stop = ean8._stop + ean8._8_start_stop_vbar = Vbar:from_int(start[1], mod, start[2]) + ean8._8_ctrl_center_vbar = Vbar:from_int(stop[1], mod, stop[2]) + ean8._8_codeset_vbar = {} + local tvbar = ean8._8_codeset_vbar + for k = 1, 3, 2 do -- only codeset A and C (k == 1, 3) + tvbar[k] = {} + local codetab = ean8._symbol[k] + local isbar = ean8._is_first_bar[k] + local tv = tvbar[k] + for i = 0, 9 do + tv[i] = Vbar:from_int(codetab[i], mod, isbar) + end + end + end, + ["5"] = function (ean5, Vbar, mod) -- add-on EAN5 + ean5._main_len = 5 + ean5._is_last_checksum = false + ean5._5_start_vbar = Vbar:from_int(112, mod, true) + ean5._5_sep_vbar = Vbar:from_int(11, mod, false) + ean5._5_codeset_vbar = {} + local tvbar = ean5._5_codeset_vbar + local symbols = ean5._symbol + for c = 1, 2 do + tvbar[c] = {} + local tcs = tvbar[c] + local isbar = false + local sb = symbols[c] + for i = 0, 9 do + tcs[i] = Vbar:from_int(sb[i], mod, false) + end + end + end, + ["2"] = function (ean2, Vbar, mod) -- add-on EAN2 + ean2._main_len = 2 + ean2._is_last_checksum = false + ean2._2_start_vbar = Vbar:from_int(112, mod, true) + ean2._2_sep_vbar = Vbar:from_int(11, mod, false) + ean2._2_codeset_vbar = {} + local tvbar = ean2._2_codeset_vbar + local symbols = ean2._symbol + for c = 1, 2 do + tvbar[c] = {} + local tcs = tvbar[c] + local isbar = false + local sb = symbols[c] + for i = 0, 9 do + tcs[i] = Vbar:from_int(sb[i], mod, false) + end + end + end, + ["13+5"] = function (ean, Vbar, mod) -- EAN13 with EAN5 add-on + config_full(ean, Vbar, mod, 13, 5) + end, + ["13+2"] = function(ean, Vbar, mod) -- EAN13 with EAN2 add-on + config_full(ean, Vbar, mod, 13, 2) + end, + ["8+5"] = function(ean, Vbar, mod) -- EAN8 with EAN5 add-on + config_full(ean, Vbar, mod, 8, 5) + end, + ["8+2"] = function(ean, Vbar, mod) -- EAN8 with EAN2 add-on + config_full(ean, Vbar, mod, 8, 2) + end, +} + +-- config function +-- create all the possible VBar object +function EAN:config(variant) --> ok, err + if not type(variant) == "string" then + return false, "[ArgErr] incorrect type for 'variant', string expected" + end + local fnconfig = self._config_variant[variant] + if not fnconfig then + return false, "[Err] EAN variant '".. variant .."' not found" + end + local Vbar = self._libgeo.Vbar -- Vbar class + local mod = self.mod + fnconfig(self, Vbar, mod) + return true, nil +end + +-- utility function + +-- the checksum of EAN8 or EAN13 code +-- 'data' is an array of digits +local function checksum_8_13(data, stop_index) + local s1 = 0; for i = 2, stop_index, 2 do + s1 = s1 + data[i] + end + local s2 = 0; for i = 1, stop_index, 2 do + s2 = s2 + data[i] + end + local sum; if stop_index % 2 == 0 then + sum = 3 * s1 + s2 + else + sum = s1 + 3 * s2 + end + return (10 - (sum % 10)) % 10 +end + +-- return the checksum digit of an EAN 5 or EAN 2 add-on +-- this digits will not be part of the code +-- 'data' is an array of digits +-- i is the index where the code starts +-- len is the length of the code +local function checksum_5_2(data, i, len) --> checksum digit or nil + if len == 5 then -- EAN 5 add-on + local c1 = data[i] + data[i + 2] + data[i + 4] + local c2 = data[i + 1] + data[i + 3] + local ck = 3 * c1 + 9 * c2 + return ck % 10 + elseif len == 2 then -- EAN 2 add-on + local ck = 10 * data[i] + data[i + 1] + return ck % 4 + end +end + +-- public methods + +-- return the checksum digit of the argument or an error +-- respect to the encoder variant EAN8 or EAN13 +-- 'n' can be an integer, a string of digits or an array of digits +function EAN:checksum(n) --> n, err + local arr; + if type(n) == "number" then + if n <= 0 then + return nil, "[ArgErr] number must be a positive integer" + end + if n - math.floor(n) > 0 then + return nil, "[ArgErr] 'n' is not an integer" + end + arr = {} + local i = 0 + while n > 0 do + i = i + 1 + arr[i] = n % 10 + n = (n - arr[i]) / 10 + end + -- array reversing + local len = #arr + 1 + for i = 1, #arr/2 do + local dt = arr[i] + arr[i] = arr[len - i] + arr[len - i] = dt + end + elseif type(n) == "table" then + if not #n > 0 then return nil, "[ArgErr] empty array" end + for _, d in ipairs(n) do + if type(d) ~= "number" then + return nil, "[ArgErr] array 'n' contains a not digit element" + end + if d < 0 or d > 9 then + return nil, "[ArgErr] array contains a not digit number" + end + end + arr = n + elseif type(n) == "string" then + arr = {} + for c in string.gmatch(n, ".") do + local d = tonumber(c) + if (not d) or d > 9 then + return nil, "[ArgErr] 's' contains a not digit char" + end + arr[#arr + 1] = d + end + else + return nil, "[ArgErr] not a number, a string or an array of digits" + end + local i = #arr + if i == 7 or i == 8 then + return checksum_8_13(arr, 7) + elseif i == 12 or i == 13 then + return checksum_8_13(arr, 12) + else + return nil, "[Err] unsuitable data length for EAN8 or EAN13 checksum" + end +end + +function EAN:get_code() --> string + local var = self._variant + local code = self.code13 -- TODO: + return table.concat(code) +end + +-- internal methods for Barcode costructors + +function EAN:_finalize() --> ok, err + local l1 = self._main_len + local l2 = self._addon_len + local ok_len = l1 + (l2 or 0) + local symb_len = self._code_len + if symb_len ~= ok_len then + return false, "[ArgErr] not a "..ok_len.."-digits long array" + end + if self._is_last_checksum then -- is the last digit ok? + local data = self._code_data + local ck = checksum_8_13(data, l1 - 1) + if ck ~= data[l1] then + return false, "[Err] wrong checksum digit" + end + end + return true, nil +end + +-- drawing functions + +EAN._append_ga_variant = {} +local fn_append_ga_variant = EAN._append_ga_variant + +-- draw EAN13 symbol +fn_append_ga_variant["13"] = function (ean, canvas, tx, ty, ax, ay) + local code = ean._code_data + local mod = ean.mod + local bars_depth = mod * ean.bars_depth_factor + local w, h = 95*mod, ean.height + bars_depth + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local y1 = y0 + h + local xpos = x0 -- current insertion x-coord + local ys = y0 + bars_depth + local s_width = 7*mod + local code_seq = ean._codeset_seq[code[1]] + -- draw the start symbol + local err + err = canvas:start_bbox_group(); assert(not err, err) + local be = ean._13_start_stop_vbar + err = canvas:encode_Vbar(be, xpos, y0, y1); assert(not err, err) + xpos = xpos + 3*mod + -- draw the first 6 numbers + for i = 2, 7 do + local codeset = code_seq[i-1] + local n = code[i] + local vbar = ean._13_codeset_vbar[codeset][n] + err = canvas:encode_Vbar(vbar, xpos, ys, y1); assert(not err, err) + xpos = xpos + s_width + end + -- draw the control symbol + local ctrl = ean._13_ctrl_center_vbar + err = canvas:encode_Vbar(ctrl, xpos, y0, y1); assert(not err, err) + xpos = xpos + 5*mod + -- draw the last 6 numbers + for i = 8, 13 do + local codeset = code_seq[i-1] + local n = code[i] + local vbar = ean._13_codeset_vbar[codeset][n] + err = canvas:encode_Vbar(vbar, xpos, ys, y1); assert(not err, err) + xpos = xpos + s_width + end + -- draw the stop char + err = canvas:encode_Vbar(be, xpos, y0, y1); assert(not err, err) + -- bounding box set up + local qzl = ean.quietzone_left_factor * mod + local qzr = ean.quietzone_right_factor * mod + local err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1) + assert(not err, err) + if ean.text_enabled then -- human readable text + local Text = ean._libgeo.Text + local txt_1 = Text:from_digit_array(code, 1, 1) + local txt_2 = Text:from_digit_array(code, 2, 7) + local txt_3 = Text:from_digit_array(code, 8, 13) + local y_bl = ys - ean.text_ygap_factor * mod + local mx = ean.text_xgap_factor + local err + err = canvas:encode_Text(txt_1, x0 - qzl, y_bl, 0, 1) + assert(not err, err) + local x2_1 = x0 + (3+mx)*mod + local x2_2 = x0 + (46-mx)*mod + err = canvas:encode_Text_xwidth(txt_2, x2_1, x2_2, y_bl, 1) + assert(not err, err) + local x3_1 = x0 + (49+mx)*mod + local x3_2 = x0 + (92-mx)*mod + err = canvas:encode_Text_xwidth(txt_3, x3_1, x3_2, y_bl, 1) + assert(not err, err) + end +end + +-- draw EAN8 symbol +fn_append_ga_variant["8"] = function (ean, canvas, tx, ty, ax, ay) + local code = ean._code_data + local mod = ean.mod + local bars_depth = mod * ean.bars_depth_factor + local w, h = 67*mod, ean.height + bars_depth + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local y1 = y0 + h + local xpos = x0 -- current insertion x-coord + local ys = y0 + bars_depth + local s_width = 7*mod + -- draw the start symbol + local err + err = canvas:start_bbox_group(); assert(not err, err) + local be = ean._8_start_stop_vbar + err = canvas:encode_Vbar(be, xpos, y0, y1); assert(not err, err) + xpos = xpos + 3*mod + -- draw the first 4 numbers + local t_vbar = ean._8_codeset_vbar + local cs14 = ean._codeset14_8 + for i = 1, 4 do + local n = code[i] + local vbar = t_vbar[cs14][n] + err = canvas:encode_Vbar(vbar, xpos, ys, y1); assert(not err, err) + xpos = xpos + s_width + end + -- draw the control symbol + local ctrl = ean._8_ctrl_center_vbar + err = canvas:encode_Vbar(ctrl, xpos, y0, y1); assert(not err, err) + xpos = xpos + 5*mod + -- draw the product code + local cs58 = ean._codeset58_8 + for i = 5, 8 do + local n = code[i] + local vbar = t_vbar[cs58][n] + err = canvas:encode_Vbar(vbar, xpos, ys, y1); assert(not err, err) + xpos = xpos + s_width + end + -- draw the stop char + err = canvas:encode_Vbar(be, xpos, y0, y1); assert(not err, err) + -- bounding box set up + local qzl = ean.quietzone_left_factor * mod + local qzr = ean.quietzone_right_factor * mod + local err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1) + assert(not err, err) + if ean.text_enabled then -- human readable text + local Text = ean._libgeo.Text + local t_1 = Text:from_digit_array(code, 1, 4) + local t_2 = Text:from_digit_array(code, 5, 8) + local y_bl = ys - ean.text_ygap_factor * mod + local mx = ean.text_xgap_factor + local x1_1 = x0 + ( 3 + mx)*mod + local x1_2 = x0 + (32 - mx)*mod + err = canvas:encode_Text_xwidth(t_1, x1_1, x1_2, y_bl, 1) + assert(not err, err) + local x2_1 = x0 + (35+mx)*mod + local x2_2 = x0 + (64-mx)*mod + err = canvas:encode_Text_xwidth(t_2, x2_1, x2_2, y_bl, 1) + assert(not err, err) + end +end + +-- draw EAN5 add-on symbol +fn_append_ga_variant["5"] = function (ean, canvas, tx, ty, ax, ay, h) + local code = ean._code_data + local l1 = ean._main_len + local i1; if l1 == 5 then + i1 = 1 + else + i1 = l1 + 1 + end + local i2 = i1 + 4 + local mod = ean.mod + local w = 47*mod + h = h or ean.height + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local y1 = y0 + h + local xpos = x0 -- current insertion x-coord + local sym_w = 7*mod + local sep_w = 2*mod + -- draw the start symbol + local err + err = canvas:start_bbox_group(); assert(not err, err) + local start = ean._5_start_vbar + err = canvas:encode_Vbar(start, xpos, y0, y1); assert(not err, err) + xpos = xpos + 4*mod + local ck = checksum_5_2(code, i1, 5) + local codeset = ean._codeset_5[ck] + local sep = ean._5_sep_vbar + local t_vbar = ean._5_codeset_vbar + -- draw the five digits + local k = 0 + for i = i1, i2 do + k = k + 1 + local cs = codeset[k] -- 1 or 2 + local d = code[i] + local vbar = t_vbar[cs][d] + err = canvas:encode_Vbar(vbar, xpos, y0, y1); assert(not err, err) + xpos = xpos + sym_w + if k < 5 then + err = canvas:encode_Vbar(sep, xpos, y0, y1); assert(not err, err) + xpos = xpos + sep_w + end + end + -- bounding box set up + local qzl = ean.quietzone_left_factor * mod + local qzr = ean.quietzone_right_factor * mod + local err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1) + assert(not err, err) + if ean.text_enabled then -- human readable text + local Text = ean._libgeo.Text + local txt = Text:from_digit_array(code, i1, i2) + local y_bl = y1 + ean.text_ygap_factor * mod + local x1_1 = x0 + 3*mod + local x1_2 = x1 - 3*mod + err = canvas:encode_Text_xwidth(txt, x1_1, x1_2, y_bl, 0) + assert(not err, err) + end +end + +-- draw EAN2 symbol +fn_append_ga_variant["2"] = function (ean, canvas, tx, ty, ax, ay, h) + local code = ean._code_data + local l1 = ean._main_len + local i1; if l1 == 2 then + i1 = 1 + else + i1 = l1 + 1 + end + local mod = ean.mod + local w = 20*mod + h = h or ean.height + local x0 = (tx or 0.0) - ax * w + local y0 = (ty or 0.0) - ay * h + local x1 = x0 + w + local y1 = y0 + h + local xpos = x0 -- current insertion x-coord + local sym_w = 7*mod + local sep_w = 2*mod + -- draw the start symbol + local err + err = canvas:start_bbox_group(); assert(not err, err) + local start = ean._2_start_vbar + err = canvas:encode_Vbar(start, xpos, y0, y1); assert(not err, err) + xpos = xpos + 4*mod + local r = checksum_5_2(code, i1, 2) + local s1, s2 + if r == 0 then -- LL scheme + s1, s2 = 1, 1 + elseif r == 1 then -- LG scheme + s1, s2 = 1, 2 + elseif r == 2 then -- GL scheme + s1, s2 = 2, 1 + else -- r == 3 -- GG scheme + s1, s2 = 2, 2 + end + local t_vbar = ean._2_codeset_vbar + local d1 = code[i1] -- render the first digit + local vb1 = t_vbar[s1][d1] + err = canvas:encode_Vbar(vb1, xpos, y0, y1); assert(not err, err) + xpos = xpos + sym_w + local sep = ean._2_sep_vbar + err = canvas:encode_Vbar(sep, xpos, y0, y1); assert(not err, err) + xpos = xpos + sep_w + local d2 = code[i1 + 1] -- render the second digit + local vb2 = t_vbar[s2][d2] + err = canvas:encode_Vbar(vb2, xpos, y0, y1); assert(not err, err) + -- bounding box set up + local qzl = ean.quietzone_left_factor * mod + local qzr = ean.quietzone_right_factor * mod + local err = canvas:stop_bbox_group(x0 - qzl, y0, x1 + qzr, y1) + assert(not err, err) + if ean.text_enabled then -- human readable text + local Text = ean._libgeo.Text + local txt = Text:from_digit_array(code, i1, i1 + 1) + local y_bl = y1 + ean.text_ygap_factor * mod + local x1_1 = x0 + 3*mod + local x1_2 = x1 - 3*mod + err = canvas:encode_Text_xwidth(txt, x1_1, x1_2, y_bl, 0) + assert(not err, err) + end +end + +fn_append_ga_variant["13+5"] = function (ean, canvas, tx, ty, ax, ay) + local mod = ean.mod + local bars_depth = mod * ean.bars_depth_factor + local h = ean.height + bars_depth + local w = (142 + ean.addon_xgap_factor) * mod + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local fn_ga = ean._append_ga_variant + local fn_1 = fn_ga["13"] + local fn_2 = fn_ga["5"] + fn_1(ean, canvas, x0, y0, 0, 0) + fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) +end + +fn_append_ga_variant["13+2"] = function (ean, canvas, tx, ty, ax, ay) + local mod = ean.mod + local bars_depth = mod * ean.bars_depth_factor + local h = ean.height + bars_depth + local w = (115 + ean.addon_xgap_factor) * mod + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local fn_ga = ean._append_ga_variant + local fn_1 = fn_ga["13"] + local fn_2 = fn_ga["2"] + fn_1(ean, canvas, x0, y0, 0, 0) + fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) +end + +fn_append_ga_variant["8+5"] = function (ean, canvas, tx, ty, ax, ay) + local mod = ean.mod + local bars_depth = mod * ean.bars_depth_factor + local h = ean.height + bars_depth + local w = (114 + ean.addon_xgap_factor) * mod + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local fn_ga = ean._append_ga_variant + local fn_1 = fn_ga["8"] + local fn_2 = fn_ga["5"] + fn_1(ean, canvas, x0, y0, 0, 0) + fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) +end + +fn_append_ga_variant["8+2"] = function (ean, canvas, tx, ty, ax, ay) + local mod = ean.mod + local bars_depth = mod * ean.bars_depth_factor + local h = ean.height + bars_depth + local w = (87 + ean.addon_xgap_factor) * mod + local x0 = (tx or 0) - ax * w + local y0 = (ty or 0) - ay * h + local x1 = x0 + w + local fn_ga = ean._append_ga_variant + local fn_1 = fn_ga["8"] + local fn_2 = fn_ga["2"] + fn_1(ean, canvas, x0, y0, 0, 0) + fn_2(ean, canvas, x1, y0, 1, 0, 0.85 * h) +end + +-- Drawing into the provided channel geometrical data +-- tx, ty is the optional translation vector +-- the function return the canvas reference to allow call chaining +function EAN:append_ga(canvas, tx, ty) --> canvas + local var = self._variant + local fn_append_ga = assert(self._append_ga_variant[var]) + local ax, ay = self.ax, self.ay + fn_append_ga(self, canvas, tx, ty, ax, ay) + return canvas +end + +return EAN diff --git a/macros/luatex/generic/barracuda/lib/lib-barcode/i2of5.lua b/macros/luatex/generic/barracuda/lib/lib-barcode/i2of5.lua new file mode 100644 index 0000000000..8097b855f7 --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-barcode/i2of5.lua @@ -0,0 +1,378 @@ +-- Interleaved 2 of 5 (ITF) barcode generator +-- +-- Copyright (C) 2019 Roberto Giacomelli +-- see LICENSE.txt file + +local ITF = { -- main container + _VERSION = "ITF v0.0.1", + _NAME = "ITF", + _DESCRIPTION = "Interleaved 2 of 5 barcode encoder", +} + +ITF._start = 111 -- nnnn +ITF._stop = 112 -- Wnn (integer must be in reverse order) + +ITF._pattern = { -- true -> narrow, false -> Wide + [0] = {true, true, false, false, true}, + [1] = {false, true, true, true, false}, + [2] = {true, false, true, true, false}, + [3] = {false, false, true, true, true}, + [4] = {true, true, false, true, false}, + [5] = {false, true, false, true, true}, + [6] = {true, false, false, true, true}, + [7] = {true, true, true, false, false}, + [8] = {false, true, true, false, true}, + [9] = {true, false, true, false, true}, +} + +-- define parameters +ITF._par_def = {} +local pardef = ITF._par_def + +-- module main parameter +pardef.module = { + -- Narrow element X-dimension is the width of the smallest element. + -- The module width (width of narrow element) should be at least 7.5 mils + -- that is exactly 0.1905mm (1 mil is 1/1000 inch). + default = 7.5 * 0.0254 * 186467, -- 7.5 mils (sp) unit misure, + unit = "sp", -- scaled point + isReserved = true, + order = 1, -- the one first to be modified + fncheck = function (self, mod, _) --> boolean, err + if mod >= self.default then return true, nil end + return false, "[OutOfRange] too small lenght for X-dim" + end, +} + +pardef.ratio = { + -- The "wide" element is a multiple of the "narrow" element that can + -- range between 2.0 and 3.0. Preferred value is 3.0. + -- The multiple for the wide element should be between 2.0 and 3.0 if the + -- narrow element is greater than 20 mils. If the narrow element is less + -- than 20 mils (0.508mm), the ratio must exceed 2.2. + default = 3.0, + unit = "absolute-number", + isReserved = true, + order = 2, + fncheck = function (_, ratio, tpardef) --> boolean, err + local mils = 0.0254 * 186467 + local mod = tpardef.module + local minr; if mod < 20*mils then minr = 2.2 else minr = 2.0 end + if ratio < minr then + return false, "[OutOfRange] too small ratio (the min is "..minr..")" + end + if ratio > 3.0 then + return false, "[OutOfRange] too big ratio (the max is 3.0)" + end + return true, nil + end, +} + +pardef.height = { + -- The height should be at least 0.15 times the barcode's length or 0.25 inch. + default = 15 * 186467, -- 15mm -- TODO: better assessment for symbol length + unit = "sp", -- scaled point + isReserved = false, + order = 3, + fncheck = function (_self, h, _opt) --> boolean, err + local mils = 0.0254 * 186467 + if h >= 250*mils then + return true, nil + end + return false, "[OutOfRange] height too small" + end, +} + +pardef.quietzone = { + -- Quiet zones must be at least 10 times the module width or 0.25 inches, + -- whichever is larger + default = 250 * 0.0254 * 186467, -- 0.25 inch (250 mils) + unit = "sp", -- scaled point + isReserved = false, + order = 4, + fncheck = function (self, qz, _opt) --> boolean, err + local mils = 0.0254 * 186467 + local mod = self.module + local min = math.max(10*mod, 250*mils) + if qz >= min then + return true, nil + else + return false, "[OutOfRange] quietzone too small" + end + end, +} + +pardef.check_digit_policy = { -- enumeration + default = "none", + isReserved = false, + policy_enum = { + add = true, -- add a check digit to the symbol + verify = true, -- check the last digit of the symbol as check digit + none = true, -- do nothing + }, + order = 5, + fncheck = function (self, e, _) --> boolean, err + if type(e) ~= "string" then return false, "[TypeError] not a string" end + local keys = self.policy_enum + if keys[e] == true then + return true, nil + else + return false, "[Err] enum value not found" + end + end, +} + +pardef.check_digit_method = { -- enumeration + -- determine the algorithm for the check digit calculation + default = "mod_10", + isReserved = false, + order = 6, + method_enum = { + mod_10 = true, -- MOD 10 check digits method + }, + fncheck = function (self, e, _) --> boolean, err + if type(e) ~= "string" then return false, "[TypeError] not a string" end + local keys = self.method_enum + if keys[e] == true then + return true, nil + else + return false, "[Err] enum value not found" + end + end, +} + +pardef.bearer_bars_enabled = { -- boolean type + -- enable/disable Bearer bars around the barcode symbol + default = false, + isReserved = false, + order = 7, + fncheck = function (_, flag, _) --> boolean, err + if type(flag) == "boolean" then + return true, nil + else + return false, "[TypeErr] not a boolean value" + end + end, +} + +pardef.bearer_bars_thickness = { -- dimension + default = 37.5 * 0.0254 * 186467, -- 5 modules + unit = "sp", -- scaled point + isReserved = false, + order = 8, + fncheck = function (_self, thick, tpardef) --> boolean, err + local module = tpardef.module + if thick >= 2*module then + return true, nil + end + return false, "[OutOfRange] thickness too small" + end, +} + +pardef.bearer_bars_layout = { -- enumeration + -- determine the algorithm for the check digit calculation + default = "hbar", + isReserved = false, + order = 9, + method_enum = { + frame = true, -- a rectangle around the symbol + hbar = true, -- top and bottom horizontal bars + }, + fncheck = function (self, e, _) --> boolean, err + if type(e) ~= "string" then return false, "[TypeError] not a string" end + local keys = self.method_enum + if keys[e] == true then + return true, nil + else + return false, "[Err] enum value not found" + end + end, +} + +-- auxiliary functions + +-- separate a non negative integer in its digits {d_n-1, ..., d_1, d_0} +local function n_to_arr(n) --> len, digits + local digits = {} + local slen + if n == 0 then + digits[#digits + 1] = 0 + slen = 1 + else + slen = 0 + while n > 0 do + local d = n % 10 + digits[#digits + 1] = d + n = (n - d) / 10 + slen = slen + 1 + end + end + for k = 1, slen/2 do -- array reversing + local h = slen - k + 1 + local d = digits[k] + digits[k] = digits[h] + digits[h] = d + end + return slen, digits +end + +local function rshift(t) + local tlen = #t + for i = tlen, 1, -1 do + t[i + 1] = t[i] + end + t[1] = 0 +end + + +local function check_mod10(t, last) + local sum = 0 + local w = true + for i = last, 1, -1 do + if w then + sum = sum + 3*t[i] + else + sum = sum + t[i] + end + w = not w + end + local m = sum % 10 + if m == 0 then return 0 else return 10 - m end +end + +local function checkdigit(t, last, method) + if method == "mod_10" then + return check_mod10(t, last) + else + assert(false, "[InternalErr] unknow method") + end +end + + +-- configuration function +function ITF:config() --> ok, err + -- init Vbar objects + local narrow = self.module + local wide = narrow * self.ratio + -- start symbol + local Vbar = self._libgeo.Vbar -- Vbar class + self._vbar_start = Vbar:from_int_revpair(self._start, narrow, wide) + self._vbar_stop = Vbar:from_int_revpair(self._stop, narrow, wide) + + -- build every possible pair of digits from 00 to 99 + self._vbar_data = {} + local vbar = self._vbar_data + local pattern = self._pattern + for dec = 0, 9 do + for unit = 0, 9 do + local t1 = pattern[dec] + local t2 = pattern[unit] + local n = dec*10 + unit + vbar[n] = Vbar:from_two_tab(t1, t2, narrow, wide) + end + end + return true, nil +end + +-- public functions + +function ITF:get_checkdigit(n, method) + if type(n) ~= "number" then return nil, "[ArgErr] 'n' is not a number" end + if n < 0 then return nil, "[ArgErr] found a negative number" end + if n - math.floor(n) ~= 0 then return nil, "[ArgErr] found a float number" end + method = method or self.check_digit_method + local last, t = n_to_arr(n) + return checkdigit(t, last, method) +end + +-- internal methods for constructors + +function ITF:_finalize() --> ok, err + -- check digit action + local policy = self.check_digit_policy + local slen = self._code_len + local is_even = (slen % 2 == 0) + local digits = self._code_data + if policy == "none" then + if not is_even then + rshift(digits) -- add a heading zero for padding + slen = slen + 1 + end + elseif policy == "add" then + if is_even then + rshift(digits) -- add a heading zero for padding + slen = slen + 1 + end + local c = checkdigit(digits, slen, self.check_digit_method) + digits[#digits + 1] = c + elseif policy == "verify" then + if not is_even then + rshift(digits) + slen = slen + 1 + end + local c = checkdigit(digits, slen - 1, self.check_digit_method) + if c ~= digits[slen] then + return false, "[DataErr] wrong check digit" + end + else + return false, "[InternalError] wrong enum value" + end + self._code_len = slen + return true, nil +end + +-- drawing function +-- tx, ty is an optional translator vector +function ITF:append_ga(canvas, tx, ty) --> canvas + local err = canvas:start_bbox_group(); assert(not err, err) + -- draw the start symbol + local xdim = self.module + local ratio = self.ratio + local symb_len = 2 * xdim * (3 + 2*ratio) + local x0 = tx or 0 + local xpos = x0 + local y0 = ty or 0 + local y1 = y0 + self.height + local start = self._vbar_start + local err + err = canvas:encode_Vbar(start, xpos, y0, y1); assert(not err, err) + xpos = xpos + 4 * xdim + -- draw the code symbol + local digits = self._code_data + local vbars = self._vbar_data + for i = 1, #digits, 2 do + local index = 10 * digits[i] + digits[i+1] + local b = vbars[index] + err = canvas:encode_Vbar(b, xpos, y0, y1); assert(not err, err) + xpos = xpos + symb_len + end + -- draw the stop symbol + local stop = self._vbar_stop + err = canvas:encode_Vbar(stop, xpos, y0, y1); assert(not err, err) + -- bounding box setting + local x1 = xpos + (2 + ratio)*xdim + local qz = self.quietzone + local b1x, b1y = x0 - qz, y0 + local b2x, b2y = x1 + qz, y1 + if self.bearer_bars_enabled then + local w = self.bearer_bars_thickness + err = canvas:encode_linethick(w); assert(not err, err) + b1y, b2y = b1y - w, b2y + w + local layout = self.bearer_bars_layout + if layout == "hbar" then + err = canvas:encode_hline(b1x, b2x, y0 - w/2); assert(not err, err) + err = canvas:encode_hline(b1x, b2x, y1 + w/2); assert(not err, err) + elseif layout == "frame" then + err = canvas:encode_rectangle(b1x - w/2, y0 - w/2, b2x + w/2, y1 + w/2) + assert(not err, err) + b1x, b2x = b1x - w, b2x + w + else + error("[IntenalErr] bearer bars layout option is wrong") + end + end + local err = canvas:stop_bbox_group(b1x, b1y, b2x, b2y) + assert(not err, err) + return canvas +end + +return ITF diff --git a/macros/luatex/generic/barracuda/lib/lib-driver/driver.lua b/macros/luatex/generic/barracuda/lib/lib-driver/driver.lua new file mode 100644 index 0000000000..956c1f1e9d --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-driver/driver.lua @@ -0,0 +1,400 @@ +-- +-- ga Intermediate Graphic Language for barcode drawing +-- Copyright (C) 2019 Roberto Giacomelli +-- +-- Basic driver interface +-- drawing elementary vector shape +-- All dimensions are in scaled point (sp) + +local Driver = { + _VERSION = "Driver v0.0.1", + _NAME = "Driver", + _DESCRIPTION = "Driver for ga graphic assembler stream", +} + +Driver.__index = Driver +Driver._drv_instance = {} -- driver instances repository + +-- driver_type/submodule name +Driver._drv_available_drv = { -- lowercase keys please + native = "lib-driver.drv-pdfliteral", -- only LuaTeX driver + svg = "lib-driver.drv-svg", + -- tikz = "lib-driver.drv-tikz", +} + +function Driver:_get_driver(id_drv) --> object, err + if type(id_drv) ~= "string" then + return nil, "[ArgErr] 'id_drv' is not a string" + end + if not self._drv_available_drv[id_drv] then + return nil, "[ArgErr] driver '"..id_drv.."' not found" + end + local t_drv = self._drv_instance + if t_drv[id_drv] then -- is the repo already loaded? + return t_drv[id_drv], nil + else -- loading driver + local module = self._drv_available_drv[id_drv] + local channel = require(module) + t_drv[id_drv] = channel + return channel, nil + end +end + +function Driver:_new_state() --> a new state + return { + line_width = 65781.76, -- line width 1bp (in scaled point sp) + line_cap = 0, -- line cap style + line_join = 0, -- line join style + gtext = false, -- text group off + bb_on = true, -- bounding box checking activation + bb_x1 = nil, -- bounding box coordinates in sp (nil means no data) + bb_y1 = nil, + bb_x2 = nil, + bb_y2 = nil, + mm = 186467.98110236, -- conversion factor sp -> mm (millimeter) + bp = 65781.76, -- conversion factor sp -> bp (big point) + } +end + +function Driver:_ga_process(drv, ga, st, bf, xt) + local op_fn = self._opcode_v001 + local pc = 1 -- program counter + local data = ga._data + while data[pc] do -- stream processing + local opcode = data[pc] + local fn = assert(op_fn[opcode], "[InternalErr] unimpl opcode ".. opcode) + pc = fn(drv, st, pc + 1, data, bf, xt) + end +end + +-- save graphic data in an external file with the 'id_drv' format +-- id_drv: specific driver output +-- ga: ga object +-- filename: file name +-- ext: file extension (optional) +function Driver:save(id_drv, ga, filename, ext) --> ok, err + -- retrive the output library + local drv, err = self:_get_driver(id_drv) + if err then return false, err end + -- init + local state = self:_new_state() + local buf, txt_buf = drv.init_buffer(state) -- a new buffer and text_buffer + -- processing + self:_ga_process(drv, ga, state, buf, txt_buf) + -- buffer finalizing + drv.close_buffer(state, buf, txt_buf) -- finalize the istruction + -- file saving + local sep = drv.buf_sep + ext = ext or drv.ext + local fn = io.open(filename.."."..ext, "w") -- output the file + fn:write(table.concat(buf, sep)) -- concat the buffer + fn:close() + return true, nil +end + +-- insert a ga drawing in a TeX box +-- PDFnative only function +function Driver:ga_to_hbox(ga, boxname) --> ok, err + -- retrive the output library + local id_drv = "native" + local drv, err = self:_get_driver(id_drv) + if err then return false, err end + -- init process + local state = self:_new_state() + local buf, txt_buf = drv.init_buffer(state) -- a new buffer and text_buffer + -- processing + self:_ga_process(drv, ga, state, buf, txt_buf) + -- finalizing + drv.close_buffer(state, buf, txt_buf) -- finalize the istruction sequence + -- build hbox + local ok, err = drv.hboxcreate(boxname, state, buf, txt_buf) + return ok, err +end + + +-- operational functions +-- _op_v001 corresponds to the version 1 of ga graphic assembler specification. +-- The table indexes every opcode to a function that takes these arguments and +-- return the updated program counter pointed to the next operation: +-- fn: format specific driver library +-- st: state +-- pc: program counter +-- ga: read only ga stream +-- bf: the output buffer +-- xt: the output text object buffer +Driver._opcode_v001 = { + [1] = function (drv, st, pc, ga, bf, xt) -- 1 <W: dim>; set line width + local w = ga[pc] + st.line_width = w + if not drv.append_001 then + error("[InternalErr] unimplemented opcode 1 for "..drv._NAME) + end + drv.append_001(st, bf, xt, w) + return pc + 1 + end, + [2] = function (drv, st, pc, ga, bf, xt) -- 2 <e: u8>; set line cap style + local style = ga[pc] + st.line_cap = style + if not drv.append_002 then + error("[InternalErr] unimplemented opcode 2 for "..drv._NAME) + end + drv.append_002(st, bf, xt, style) + return pc + 1 + end, + [3] = function (drv, st, pc, ga, bf, xt) -- 3 <e: u8>; set line join style + local join = ga[pc] + if not drv.append_003 then + error("[InternalErr] unimplemented opcode 3 for "..drv._NAME) + end + drv.append_003(st, bf, xt, join) + return pc + 1 + end, + [30] = function (drv, st, pc, ga, bf, xt) -- start_bbox_group + assert(st.bb_on) + st.bb_on = false + return pc + end, + [31] = function (drv, st, pc, ga, bf, xt) -- end_bbox_group + assert(st.bb_on == false) + st.bb_on = true + local x1 = ga[pc]; pc = pc + 1 + local y1 = ga[pc]; pc = pc + 1 + local x2 = ga[pc]; pc = pc + 1 + local y2 = ga[pc]; pc = pc + 1 + if st.bb_x1 == nil then + st.bb_x1 = x1 + st.bb_y1 = y1 + st.bb_x2 = x2 + st.bb_y2 = y2 + else + if x1 < st.bb_x1 then st.bb_x1 = x1 end + if x2 > st.bb_x2 then st.bb_x2 = x2 end + if y1 < st.bb_y1 then st.bb_y1 = y1 end + if y2 > st.bb_y2 then st.bb_y2 = y2 end + end + return pc + end, + -- draw an horizontal line + -- 33 <x1: DIM> <x2: DIM> <y: DIM> + [33] = function (drv, st, pc, ga, bf, xt) + local x1 = ga[pc]; pc = pc + 1 + local x2 = ga[pc]; pc = pc + 1 + local y = ga[pc]; pc = pc + 1 + if st.bb_on then -- eventually update bbox + local hw = st.line_width/2 + local by1 = y - hw + local by2 = y + hw + if st.bb_x1 == nil then + st.bb_x1 = x1 + st.bb_x2 = x2 + st.bb_y1 = by1 + st.bb_y2 = by2 + else + if x1 < st.bb_x1 then st.bb_x1 = x1 end + if x2 > st.bb_x2 then st.bb_x2 = x2 end + if by1 < st.bb_y1 then st.bb_y1 = by1 end + if by2 > st.bb_y2 then st.bb_y2 = by2 end + end + end + if not drv.append_033 then + error("[InternalErr] unimplemented opcode 33 for "..drv._NAME) + end + drv.append_033(st, bf, xt, x1, x2, y) + return pc + end, + -- draw a vertical line + [34] = function (drv, st, pc, ga, bf, xt) -- 34 <y1: DIM> <y2: DIM> <x: DIM> + local y1 = ga[pc]; pc = pc + 1 + local y2 = ga[pc]; pc = pc + 1 + local x = ga[pc]; pc = pc + 1 + if st.bb_on then -- eventually update the figure bounding box + local hw = st.line_width/2 + local bx1 = x - hw + local bx2 = x + hw + if st.bb_x1 == nil then + st.bb_x1 = bx1 + st.bb_x2 = bx2 + st.bb_y1 = y1 + st.bb_y2 = y2 + else + if bx1 < st.bb_x1 then st.bb_x1 = bx1 end + if bx2 > st.bb_x2 then st.bb_x2 = bx2 end + if y1 < st.bb_y1 then st.bb_y1 = y1 end + if y2 > st.bb_y2 then st.bb_y2 = y2 end + end + end + if not drv.append_034 then + error("[InternalErr] unimplemented opcode 34 for "..drv._NAME) + end + drv.append_034(st, bf, xt, y1, y2, x) + return pc + end, + -- draw a group of vertical lines (vbar) + -- 36 <y1: DIM> <y2: DIM> <b: UINT> <x1: DIM> <t1: DIM> + [36] = function(drv, st, pc, ga, bf, xt) -- vbar + local y1 = ga[pc]; pc = pc + 1 + local y2 = ga[pc]; pc = pc + 1 + local nbar = ga[pc]; pc = pc + 1 + assert(nbar > 0) + local h = y2 - y1 -- height common to every rectangle + assert(h > 0) + local pc_next = pc + 2 * nbar + if drv.append_036_start then + drv.append_036_start(st, bf, xt, nbar, y1, y2) + end + local bx1, bx2 + for i = pc, pc_next - 1, 2 do -- reading coordinates <x axis> <width> + local x = assert(ga[i], "[InternalErr] ga prematurely reached the end") + local w = assert(ga[i+1], "[InternalErr] ga prematurely reached the end") + drv.append_036_bar(st, bf, xt, x, w, y1, y2) + -- check the bounding box only if the corresponding flag is true + local x1 = x - w/2 + local x2 = x + w/2 + if st.bb_on then + if bx1 == nil then + bx1 = x1 + bx2 = x2 + else + if x1 < bx1 then bx1 = x1 end + if x2 > bx2 then bx2 = x2 end + end + end + end + if drv.append_036_stop then + drv.append_036_stop(st, bf, xt, nbar, y1, y2) + end + if st.bb_on then -- eventually update bbox + if st.bb_x1 == nil then + st.bb_x1 = bx1 + st.bb_x2 = bx2 + st.bb_y1 = y1 + st.bb_y2 = y2 + else + if bx1 < st.bb_x1 then st.bb_x1 = bx1 end + if bx2 > st.bb_x2 then st.bb_x2 = bx2 end + if y1 < st.bb_y1 then st.bb_y1 = y1 end + if y2 > st.bb_y2 then st.bb_y2 = y2 end + end + end + return pc_next + end, + -- draw a rectangle + -- 48 <x1: DIM> <y1: DIM> <x2: DIM> <y2: DIM> + [48] = function(drv, st, pc, ga, bf, xt) + local x1 = ga[pc]; pc = pc + 1 + local y1 = ga[pc]; pc = pc + 1 + local x2 = ga[pc]; pc = pc + 1 + local y2 = ga[pc]; pc = pc + 1 + -- check the bounding box only if the flag is true + if st.bb_on then + local hw = st.line_width/2 + local bx1, bx2 = x1 - hw, x2 + hw + local by1, by2 = y1 - hw, y2 + hw + if st.bb_x1 == nil then + st.bb_x1 = bx1 + st.bb_x2 = bx2 + st.bb_y1 = by1 + st.bb_y2 = by2 + else + if bx1 < st.bb_x1 then st.bb_x1 = bx1 end + if bx2 > st.bb_x2 then st.bb_x2 = bx2 end + if by1 < st.bb_y1 then st.bb_y1 = by1 end + if by2 > st.bb_y2 then st.bb_y2 = by2 end + end + end + if not drv.append_048 then + error("[InternalErr] unimplemented opcode 48 for "..drv._NAME) + end + drv.append_048(st, bf, xt, x1, y1, x2, y2) + return pc + end, + -- text + [130] = function(drv, st, pc, ga, bf, xt) -- text: ax ay xpos ypos string + local ax = ga[pc]; pc = pc + 1 + local ay = ga[pc]; pc = pc + 1 + local xpos = ga[pc]; pc = pc + 1 + local ypos = ga[pc]; pc = pc + 1 + assert(ga[pc] ~= 0, "[InternalErr] empty chars sequence") + while ga[pc] ~= 0 do + local c = ga[pc]; pc = pc + 1 + drv.append_130_char(st, bf, xt, c) + end + local x1, y1, x2, y2 = drv.append_130_stop(st, bf, xt, xpos, ypos, ax, ay) + -- bounding box checking + if st.bb_on then + if st.bb_x1 == nil then + st.bb_x1 = x1 + st.bb_x2 = x2 + st.bb_y1 = y1 + st.bb_y2 = y2 + else + if x1 < st.bb_x1 then st.bb_x1 = x1 end + if x2 > st.bb_x2 then st.bb_x2 = x2 end + if y1 < st.bb_y1 then st.bb_y1 = y1 end + if y2 > st.bb_y2 then st.bb_y2 = y2 end + end + end + return pc + 1 + end, + [131] = function(drv, st, pc, ga, bf, xt) -- text_xspaced x1 xgap ay ypos chars + local x1 = ga[pc]; pc = pc + 1 + local xgap = ga[pc]; pc = pc + 1 + local ay = ga[pc]; pc = pc + 1 + local ypos = ga[pc]; pc = pc + 1 + assert(ga[pc] ~= 0, "[InternalErr] empty chars sequence") + while ga[pc] ~= 0 do + local c = ga[pc]; pc = pc + 1 + drv.append_131_char(st, bf, xt, c, xgap) + end + local bx1, by1, bx2, by2 = drv.append_131_stop(st, bf, xt, x1, xgap, ypos, ay) + -- bounding box checking + if st.bb_on then -- eventually update bbox + if st.bb_x1 == nil then + st.bb_x1 = bx1 + st.bb_x2 = bx2 + st.bb_y1 = by1 -- no depth + st.bb_y2 = by2 + else + if bx1 < st.bb_x1 then st.bb_x1 = bx1 end + if bx2 > st.bb_x2 then st.bb_x2 = bx2 end + if by1 < st.bb_y1 then st.bb_y1 = by1 end + if by2 > st.bb_y2 then st.bb_y2 = by2 end + end + end + return pc + 1 + end, + -- text_xwidth + -- <ay: FLOAT> <x1: DIM> <x2: DIM> <y: DIM> <c: CHARS> + [132] = function (drv, st, pc, ga, bf, xt) + local ay = ga[pc]; pc = pc + 1 -- y anchor + local x1 = ga[pc]; pc = pc + 1 -- left limit + local x2 = ga[pc]; pc = pc + 1 -- right limit + assert (x1 ~= x2, "[InternalErr] x coordinate are equal") + assert (x1 < x2, "[InternalErr] not ordered x1, x2 limits") + local ypos = ga[pc]; pc = pc + 1 -- y coordinate of anchor point + assert(ga[pc] ~= 0, "[InternalErr] empty chars sequence") + while ga[pc] ~= 0 do + local c = ga[pc]; pc = pc + 1 + drv.append_132_char(st, bf, xt, c) + end + local bx1, by1, bx2, by2 = drv.append_132_stop(st, bf, xt, x1, x2, ypos, ay) + -- bounding box checking + if st.bb_on then -- eventually update bbox + if st.bb_x1 == nil then + st.bb_x1 = bx1 + st.bb_x2 = bx2 + st.bb_y1 = by1 -- no depth + st.bb_y2 = by2 + else + if bx1 < st.bb_x1 then st.bb_x1 = bx1 end + if bx2 > st.bb_x2 then st.bb_x2 = bx2 end + if by1 < st.bb_y1 then st.bb_y1 = by1 end + if by2 > st.bb_y2 then st.bb_y2 = by2 end + end + end + return pc + 1 + end, +} + +return Driver + diff --git a/macros/luatex/generic/barracuda/lib/lib-driver/drv-pdfliteral.lua b/macros/luatex/generic/barracuda/lib/lib-driver/drv-pdfliteral.lua new file mode 100644 index 0000000000..50baea1472 --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-driver/drv-pdfliteral.lua @@ -0,0 +1,284 @@ +-- +-- ga graphic assembler or +-- Intermediate Graphic Language for barcode drawing +-- Copyright (C) 2019 Roberto Giacomelli +-- +-- All dimensions are in scaled point (sp) +-- ga LuaTeX Driver (native implementation node+pdfliteral) + +-- class for drawing elementary geometric elements +local PDFnative = { + _VERSION = "PDFnative v0.0.4", + _NAME = "PDFnative", + _DESCRIPTION = "A LuaTeX native pdfliteral driver for ga graphic stream", +} + +PDFnative.ext = "txt" -- file extension +PDFnative.buf_sep = "\n" -- separation string for buffer concat + +function PDFnative.init_buffer(st) --> buffer, text buffer + st.head = nil -- addition for text processing (to remember purpose) + st.last = nil + st.hbox = nil + st.cw = nil + st.x_hbox = nil + st.char_counter = nil + local bf = {"q"} -- create a new graphic stack + local xt = {} -- text buffer + return bf, xt +end + +function PDFnative.close_buffer(st, bf, xt) + bf[#bf + 1] = "Q" -- stack restoring +end + +-- text utility special functions + +local function newglue(w) --> node + local n = node.new("glue") + n.width = w + return n +end + +local function newglyph(c) --> node -- ? U+2423 ␣ for whitespace? + if c == 32 then + return newglue(tex.sp "3.5pt") + end + local n = node.new("glyph") + n.char = c + n.font = font.current() + return n +end + +local function newpdfliteral(buf) --> node + local npdf = node.new("whatsit", "pdf_literal") + npdf.mode = 0 + npdf.data = table.concat(buf, "\n") + return npdf +end + +local function append_glyph(head, last, c) --> head, last, xdim + if c == 32 then -- space + local space = tex.sp "3.5pt" + head, last = node.insert_after(head, last, newglue(space)) + return head, last, space + else + local g = newglyph(c) + local xdim = g.width + head, last = node.insert_after(head, last, g) + return head, last, xdim + end +end + +-- special drawing function +function PDFnative.hboxcreate(hboxname, st, buf, txt) --> ok, err + local node = assert(node, "This is not LuaTeX!") + local tex = assert(tex) + local font = assert(font) + if not tex.isbox(hboxname) then + return nil, string.format("Box register [%s] doesn’t exist", hboxname) + end + local bb_x1, bb_y1, bb_x2, bb_y2 = st.bb_x1, st.bb_y1, st.bb_x2, st.bb_y2 + local npdf = newpdfliteral(buf) -- node whatsit pdfliteral + -- vboxing, vertical correction + local vpdf = node.vpack(npdf) + vpdf.height = -bb_y1 + -- glue, for horizontal correction + local ng = newglue(-bb_x1) + local head, last = node.insert_after(ng, ng, vpdf) + local xprev = 0.0 + for _, t in ipairs(txt) do -- text processing + local gy = newglue(t[3] - bb_y1) -- n, x, y, w, h -- t[3] -t[5] - bb_y1 + local nvtxt = node.insert_after(t[1], t[1], gy) + local vtxt = node.vpack(nvtxt) + local gx = newglue(t[2]-xprev) + head, last = node.insert_after(head, last, gx) + head, last = node.insert_after(head, last, vtxt) + xprev = t[2] + t[4] + end + -- hboxing + local hbox = node.hpack(head) + hbox.width = bb_x2 - bb_x1 + hbox.height = bb_y2 - bb_y1 + tex.box[hboxname] = hbox + return true, nil +end + +-- PDF literal encoding functions + +-- 1 <W: dim>; set line width +function PDFnative.append_001(st, bf, xt, w) + local bp = st.bp -- 1bp (sp) + bf[#bf + 1] = string.format("%0.6f w", w/bp) +end + +-- 2 <enum: u8>; set line cap style +function PDFnative.append_002(st, bf, xt, cap) + bf[#bf + 1] = string.format("%d J", cap) +end + +-- 3 <enum: u8>; set line join style +function PDFnative.append_003(st, bf, xt, j) + bf[#bf + 1] = string.format("%d j", j) +end + +-- draw an horizontal line +-- 33 <x1: DIM> <x2: DIM> <y: DIM> +function PDFnative.append_033(st, bf, xt, x1, x2, y) + local bp = st.bp -- conversion factor bp -> sp + bf[#bf + 1] = string.format("% 0.6f %0.6f m", x1/bp, y/bp) + bf[#bf + 1] = string.format("% 0.6f %0.6f l", x2/bp, y/bp) + bf[#bf + 1] = "S" -- stroke +end + +-- vline +-- draw a vertical line +-- 34 <y1: DIM> <y2: DIM> <x: DIM> +function PDFnative.append_034(st, bf, xt, y1, y2, x) + local bp = st.bp -- conversion factor bp -> sp + bf[#bf + 1] = string.format("% 0.6f %0.6f m", x/bp, y1/bp) + bf[#bf + 1] = string.format("% 0.6f %0.6f l", x/bp, y2/bp) + bf[#bf + 1] = "S" -- stroke +end + +-- Vbar +-- draw a group of vertical lines +-- 36 <y1: DIM> <y2: DIM> <b: UINT> <x1: DIM> <t1: DIM> ... +function PDFnative.append_036_bar(st, bf, xt, x, w, y1, y2) + local bp = st.bp -- conversion factor bp -> sp + local fmt = "%0.6f %0.6f %0.6f %0.6f re" + local x1 = x - w/2 + local h = y2 - y1 + -- pdf literal insertion <x y w h re> + bf[#bf + 1] = string.format(fmt, x1/bp, y1/bp, w/bp, h/bp) +end +function PDFnative.append_036_stop(st, bf, xt, nbar, y1, y2) + bf[#bf + 1] = "f" -- fill + bf[#bf + 1] = "S" -- stroke +end + +-- draw a rectangle +-- 48 <x1: DIM> <y1: DIM> <x2: DIM> <y2: DIM> +function PDFnative.append_048(st, bf, xt, x1, y1, x2, y2) + local w = x2 - x1 -- rectangle width + assert(w > 0) + local h = y2 - y1 -- rectangle height + assert(h > 0) + local bp = st.bp -- conversion factor + local fmt = "%0.6f %0.6f %0.6f %0.6f re S" + -- pdf literal string <x y w h re> + bf[#bf + 1] = string.format(fmt, x1/bp, y1/bp, w/bp, h/bp) +end + +-- 130 <text> Text with several glyphs +-- 130 <ax: FLOAT> <ay: FLOAT> <xpos: DIM> <ypos: DIM> <c: CHARS> +function PDFnative.append_130_char(st, bf, xt, c) + local head, last = st.head, st.last + head, last = append_glyph(head, last, c) + st.head = head + st.last = last +end +-- return bounding box of the text object without deep +function PDFnative.append_130_stop(st, bf, xt, xpos, ypos, ax, ay) + local head = assert(st.head) + st.head = nil -- reset temporary reference + st.last = nil + local hbox = node.hpack(head) + local w, h, d = node.dimensions(hbox) + local x1 = xpos - ax*w -- text position + local y1; if ay > 0 then + y1 = ypos - h*ay + else + y1 = ypos - d*ay + end + xt[#xt + 1] = {hbox, x1, y1 - d, w, h} + return x1, y1, x1 + w, y1 + h +end + +-- 131 <text_xspaced>, Text with glyphs equally spaced on its vertical axis +-- 131 <x1: DIM> <xgap: DIM> <ay: FLOAT> <ypos: DIM> <c: CHARS> +function PDFnative.append_131_char(st, bf, xt, c, xgap) + local head, last, prec_cw = st.head, st.last, st.cw + local cw + if prec_cw then + local g = newglyph(c) + cw = g.width + local isp = xgap - (cw + prec_cw)/2 + local s = newglue(isp) + head, last = node.insert_after(head, last, s) + head, last = node.insert_after(head, last, g) + else -- first char + head, last, cw = append_glyph(head, last, c) + st.x_hbox = cw/2 + end + st.cw = cw + st.head = head + st.last = last +end +function PDFnative.append_131_stop(st, bf, xt, x1, xgap, ypos, ay) --> bb + local head = assert(st.head) + st.head = nil -- reset temporary reference + st.last = nil + st.cw = nil + local hbox = node.hpack(head) + local w, h, d = node.dimensions(hbox) + local bx1 = x1 - st.x_hbox + st.x_hbox = nil -- reset temporary references + local y1; if ay > 0 then + y1 = ypos - h*ay + else + y1 = ypos - d*ay + end + xt[#xt + 1] = {hbox, bx1, y1 - d, w, h} + return bx1, y1, bx1 + w, y1 + h +end + +-- 132 <text_xwidth> Glyphs equally spaced on vertical axis between two x coordinates +-- 132 <ay: FLOAT> <x1: DIM> <x2: DIM> <y: DIM> <c: CHARS> +function PDFnative.append_132_char(st, bf, xt, c) + local head, last = st.head, st.last + if head then + local g = newglyph(c) + local s = newglue(1) + head, last = node.insert_after(head, last, s) + head, last = node.insert_after(head, last, g) + st.char_counter = st.char_counter + 1 + else -- first char + head, last, cw = append_glyph(head, last, c) + st.cw = cw + st.char_counter = 1 + end + st.head = head + st.last = last +end +function PDFnative.append_132_stop(st, bf, xt, x1, x2, ypos, ay) --> p1, p2 + local head, last = st.head, st.last + st.head = nil -- reset temporary registry + st.last = nil + local w_1 = st.cw + st.cw = nil + local i = st.char_counter + st.char_counter = nil + local w_n = last.width + local xgap = (x2 - x1 - (w_1 + w_n)/2)/(i - 1) + local c_curr = head + for _ = 1, i - 1 do + local g = c_curr.next + local c_next = g.next + local w_2 + w_1, w_2 = c_curr.width, c_next.width + g.width = xgap - (w_1 + w_2)/2 + c_curr = c_next + end + local hbox = node.hpack(head) + local w, h, d = node.dimensions(hbox) + local y; if ay > 0 then + y = ypos - h*ay + else + y = ypos - d*ay + end + xt[#xt + 1] = {hbox, x1, y - d, w, h} + return x1, y, x2, y + h +end + +return PDFnative diff --git a/macros/luatex/generic/barracuda/lib/lib-driver/drv-svg.lua b/macros/luatex/generic/barracuda/lib/lib-driver/drv-svg.lua new file mode 100644 index 0000000000..7a2c5ab112 --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-driver/drv-svg.lua @@ -0,0 +1,260 @@ +-- +-- ga Intermediate Graphic Language for barcode drawing +-- SVG library +-- Copyright (C) 2019 Roberto Giacomelli +-- +-- All dimension in the ga stream are scaled point (sp) +-- 1 pt = 65536 sp + +-- class for drawing elementary geometric elements +local SVG = { + _VERSION = "SVGdriver v0.0.1", + _NAME = "SVGdriver", + _DESCRIPTION = "A SVG driver for the ga graphic stream", +} + +SVG.ext = "svg" -- file extension +SVG.buf_sep = nil -- separation string for buffer concat + +function SVG.init_buffer(st) --> buffer, text buffer + local bf = { + '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n', + '<!-- Created with Barracuda package (https://github.com/robitex/barracuda) -->\n', + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"\n', + ' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n', + '<svg xmlns="http://www.w3.org/2000/svg"\n', + ' version="1.1"\n', + ' width="%0.6fmm" height="%0.6fmm"\n', -- line 7 + ' viewBox="%0.6f %0.6f %0.6f %0.6f"\n', -- line 8 + '>\n', + } + -- additions for SVG driver to 'state' + st.ident_lvl = 1 -- identation level + st.char_buf = nil + local mm = st.mm + st.h_char = 2.1 * mm -- char height (mm) + st.w_char = st.h_char / 1.303 -- avg char width (mm) + st.d_char = st.h_char / 3.7 -- char deep (mm) + return bf, {} +end + +function SVG.close_buffer(st, bf, xt) + bf[#bf + 1] = '</svg>\n' -- close svg xml element + bf[#bf + 1] = '\n' -- a last empty line + local mm = st.mm + local x1, y1, x2, y2 = st.bb_x1, st.bb_y1, st.bb_x2, st.bb_y2 + local w = (x2 - x1)/mm + local h = (y2 - y1)/mm + local fmt_wh = bf[7] + bf[7] = string.format(fmt_wh, w, h) -- line 7 + local x, y = x1/mm, -y2/mm + local fmt_vw = bf[8] + bf[8] = string.format(fmt_vw, x, y, w, h) +end + +-- SVG encoding functions + +-- 1 <W: dim>; set line width +function SVG.append_001(st, bf, xt, w) + -- nothing to do +end + +-- draw an horizontal line +-- 33 <x1: DIM> <x2: DIM> <y: DIM> +function SVG.append_033(st, bf, xt, x1, x2, y) + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) -- a couple of spaces as indentation + local mm = st.mm -- conversion ratio sp -> bp + bf[#bf + 1] = string.format( -- <path> element + '%s<path d="M%0.6f %0.6fH%0.6f"\n', + ident, x1/mm, -y/mm, x2/mm + ) + local lw = st.line_width + bf[#bf + 1] = string.format( + '%s style="stroke:#000000;stroke-width:%0.6f"\n', + ident, lw/mm + ) + bf[#bf + 1] = ident..'/>\n' +end + +-- Vertical line: 34 <y1: DIM> <y2: DIM> <x: DIM> +function SVG.append_034(st, bf, xt, y1, y2, x) + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) -- a couple of spaces as indentation + local mm = st.mm -- conversion ratio sp -> mm + bf[#bf + 1] = string.format( -- <path> element + '%s<path d="M%0.6f %0.6fV%0.6f"\n', + ident, x/mm, -y2/mm, -y1/mm + ) + local lw = st.line_width + bf[#bf + 1] = string.format( + '%s style="stroke:#000000;stroke-width:%0.6f"\n', + ident, lw/mm + ) + bf[#bf + 1] = ident..'/>\n' +end + +-- Vbar +-- draw a group of vertical lines +-- 36 <y1: DIM> <y2: DIM> <b: UINT> <x1: DIM> <t1: DIM> ... +function SVG.append_036_start(st, bf, xt, nbar, y1, y2) + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) + bf[#bf + 1] = ident..'<g stroke="black">\n' -- open a group + st.ident_lvl = lvl + 1 +end +function SVG.append_036_bar(st, bf, xt, x, w, y1, y2) + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) + local mm = st.mm -- conversion factor mm -> sp + bf[#bf + 1] = string.format( + '%s<path d="M%0.6f %0.6fV%0.6f" style="stroke-width:%0.6f"/>\n', + ident, x/mm, -y2/mm, -y1/mm, w/mm + ) +end +function SVG.append_036_stop(st, bf, xt, nbar, y1, y2) + st.ident_lvl = st.ident_lvl - 1 + local ident = string.rep(" ", st.ident_lvl) + bf[#bf + 1] = ident..'</g>\n' -- end group +end + +-- Text +-- 130 <text> Text with several glyphs +-- 130 <ax: FLOAT> <ay: FLOAT> <xpos: DIM> <ypos: DIM> <c: CHARS> +function SVG.append_130_char(st, bf, xt, c) + local ch = string.char(c) + if not st.char_buf then + st.char_buf = {ch} + else + local chars = st.char_buf + chars[#chars + 1] = ch + end +end +function SVG.append_130_stop(st, bf, xt, xpos, ypos, ax, ay) --> p1, p2 + local c = st.char_buf + st.char_buf = nil + local txt = table.concat(c) + local w = st.w_char * #c -- approx dim + local h = st.h_char + local d = st.d_char + local anchor = "" + local x1 = xpos + local bx1 = xpos + if ax == 0 then -- start (default) + elseif ax == 0.5 then -- middle + anchor = ' text-anchor="middle"' + bx1 = bx1 - w/2 + elseif ax == 1 then -- end + anchor = ' text-anchor="end"' + bx1 = bx1 - w + else + x1 = x1 - ax*w + bx1 = x1 + end + local y1 = ypos + if ay > 0 then + y1 = y1 - h*ay + else + y1 = y1 - d*ay + end + local fs = st.h_char * 1.37 -- sp + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) + local mm = st.mm + bf[#bf + 1] = string.format( + '%s<text x="%0.6f" y="%0.6f" font-family="Verdana" font-size="%0.6f"%s>\n', + ident, x1/mm, -y1/mm, fs/mm, anchor + ) + bf[#bf + 1] = ident..txt + bf[#bf + 1] = ident..'</text>\n' + return bx1, y1, bx1 + w, y1 + h +end + +-- 131 <text_xspaced>, Text with glyphs equally spaced on its vertical axis +-- 131 <x1: DIM> <xgap: DIM> <ay: FLOAT> <ypos: DIM> <c: CHARS> +function SVG.append_131_char(st, bf, xt, c, xgap) + local ch = string.char(c) + if not st.char_buf then + st.char_buf = {ch} + else + local chars = st.char_buf + chars[#chars + 1] = ch + end +end +function SVG.append_131_stop(st, bf, xt, x1, xgap, ypos, ay) --> p1, p2 + local chars = st.char_buf + st.char_buf = nil + local n = #chars + local h = st.h_char -- height + local d = st.d_char -- deep + local hw = st.w_char/2 -- sp half width + local y1 = ypos + if ay > 0 then + y1 = y1 - h*ay + else + y1 = y1 - d*ay + end + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) + local fs = st.h_char * 1.37 -- (sp) font-size -> inter baselines distance + local mm = st.mm + bf[#bf + 1] = string.format( + '%s<text y="%0.6f" font-family="Verdana" font-size="%0.6f" text-anchor="middle">\n', + ident, -y1/mm, fs/mm + ) + local x = x1 + for _, c in ipairs(chars) do + bf[#bf + 1] = string.format('%s<tspan x="%0.6f">%s</tspan>\n', + ident, x/mm, c + ) + x = x + xgap + end + bf[#bf + 1] = ident..'</text>\n' + local x2 = x1 + (n - 1)*xgap -- sp + return x1 - hw, y1, x2 + hw, y1 + h -- text group bounding box +end + +-- 132 <text_xwidth> Glyphs equally spaced on vertical axis between two x coordinates +-- 132 <ay: FLOAT> <x1: DIM> <x2: DIM> <y: DIM> <c: CHARS> +function SVG.append_132_char(st, bf, xt, c, xgap) + local ch = string.char(c) + if not st.char_buf then + st.char_buf = {ch} + else + local chars = st.char_buf + chars[#chars + 1] = ch + end +end +function SVG.append_132_stop(st, bf, xt, x1, x2, ypos, ay) --> p1, p2 + local chars = st.char_buf; st.char_buf = nil + local n = #chars + local h = st.h_char -- height (approx) + local d = st.d_char -- deep (approx) + local cw = st.w_char -- (sp) char width (approx) + local xgap = (x2 - x1 - cw)/(n - 1) + local y1 = ypos + if ay > 0 then + y1 = y1 - h*ay + else + y1 = y1 - d*ay + end + local lvl = st.ident_lvl + local ident = string.rep(" ", lvl) + local fs = st.h_char * 1.37 -- font-size -> inter baselines distance + local mm = st.mm + bf[#bf + 1] = string.format( + '%s<text y="%0.6f" font-family="Verdana" font-size="%0.6f" text-anchor="middle">\n', + ident, -y1/mm, fs/mm + ) + local x = x1 + cw/2 + for _, c in ipairs(chars) do + bf[#bf + 1] = string.format('%s<tspan x="%0.6f">%s</tspan>\n', + ident, x/mm, c + ) + x = x + xgap + end + bf[#bf + 1] = ident..'</text>\n' + return x1, y1, x2, y1 + h -- text group bounding box +end + +return SVG diff --git a/macros/luatex/generic/barracuda/lib/lib-geo/gacanvas.lua b/macros/luatex/generic/barracuda/lib/lib-geo/gacanvas.lua new file mode 100644 index 0000000000..cccc68f447 --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-geo/gacanvas.lua @@ -0,0 +1,340 @@ +-- class gaCanvas +-- Copyright (C) 2019 Roberto Giacomelli + +-- ga -- basic function + +local gaCanvas = { + _VERSION = "gacanvas v0.0.4", + _NAME = "gaCanvas", + _DESCRIPTION = "A library for dealing with ga stream", +} +gaCanvas.__index = gaCanvas + +-- ga specification: see the file ga-grammar.pdf in the doc directory + +-- gaCanvas constructor +function gaCanvas:new() --> object + local o = { + _data = {}, + _v = 100, -- version of the ga format + } + setmetatable(o, self) + return o +end + +-- Ipothetical another constructor +-- function gaCanvas:from_tcp_server() --> err +-- end + +-- line width: opcode <1> <w: DIM> +function gaCanvas:encode_linethick(w) --> err + if type(w) ~= "number" then return "[ArgErr] 'w' number expected" end + if w < 0 then return "[ArgErr] negative value for 'w'" end + local data = self._data + data[#data + 1] = 1 -- opcode for line thickness + data[#data + 1] = w +end + +-- line cap style: opcode <2> <cap: u8> +-- 0 Butt cap +-- 1 Round cap +-- 2 Projecting square cap +function gaCanvas:encode_linecap(cap) --> err + if type(cap) ~= "number" then return "[ArgErr] 'cap' arg number expected" end + if cap == 0 or cap == 1 or cap == 2 then + local data = self._data + data[#data + 1] = 2 -- opcode for line cap style + data[#data + 1] = cap + else + return "[ArgErr] invalid value for 'cap'" + end +end + +-- line cap style: opcode <3> <join: u8> +-- 0 Miter join +-- 1 Round join +-- 2 Bevel join +function gaCanvas:encode_linejoin(join) --> err + if type(join) ~= "number" then return "[ArgErr] 'join' arg number expected" end + if join == 0 or join == 1 or join == 2 then + local data = self._data + data[#data + 1] = 3 -- opcode for line join style + data[#data + 1] = join + else + return "[ArgErr] invalid value for 'join'" + end +end + +-- Stop checking the bounding box +-- opcode: <30> +function gaCanvas:start_bbox_group() --> err + local data = self._data + data[#data + 1] = 30 +end + +-- restart checking the bounding box +-- and insert the specified bb for the entire object group +-- code: <31> x1 y1 x2 y2 +function gaCanvas:stop_bbox_group(x1, y1, x2, y2) --> err + if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end + if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end + if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end + if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end + if x1 > x2 then x1, x2 = x2, x1 end -- reorder coordinates + if y1 > y2 then y1, y2 = y2, y1 end + local data = self._data + data[#data + 1] = 31 -- bounding box of the object group + data[#data + 1] = x1 + data[#data + 1] = y1 + data[#data + 1] = x2 + data[#data + 1] = y2 +end + +-- insert a line from point (x1, y1) to the point (x2, y2) +-- <32> x1 y1 x2 y2 +function gaCanvas:encode_line(x1, y1, x2, y2) --> err + if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end + if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end + if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end + if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end + local data = self._data + data[#data + 1] = 32 -- append line data + data[#data + 1] = x1 + data[#data + 1] = y1 + data[#data + 1] = x2 + data[#data + 1] = y2 +end + +-- insert an horizontal line from point (x1, y) to point (x2, y) +-- <33> x1 x2 y +function gaCanvas:encode_hline(x1, x2, y) --> err + if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end + if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end + if type(y) ~= "number" then return "[ArgErr] 'y2' number expected" end + local data = self._data + data[#data + 1] = 33 -- append hline data + data[#data + 1] = x1 + data[#data + 1] = x2 + data[#data + 1] = y +end + +-- insert a rectangle from point (x1, x2) to (x2, y2) +-- <48> <x1: DIM> <y1: DIM> <x2: DIM> <y2: DIM> +function gaCanvas:encode_rectangle(x1, y1, x2, y2) --> err + if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end + if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end + if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end + if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end + local d = self._data + d[#d + 1] = 48 -- append rectangle data + d[#d + 1] = x1 + d[#d + 1] = y1 + d[#d + 1] = x2 + d[#d + 1] = y2 +end + +-- Vbar object: opcode <36> +-- x0, y1, y2 ordinates +function gaCanvas:encode_Vbar(vbar, x0, y1, y2) --> err + if type(vbar) ~= "table" then + return "[ArgErr] table expected for 'vbar'" + end + if x0 == nil then + x0 = 0 + elseif type(x0) ~= "number" then + return "[ArgErr] 'x0' number expected" + end + if type(y1) ~= "number" then return "[ArgErr] 'y1' number expected" end + if type(y2) ~= "number" then return "[ArgErr] 'y2' number expected" end + -- ordinates + if y1 == y2 then return "[ArgErr] 'y1' 'y2' are the same value" end + if y1 > y2 then y1, y2 = y2, y1 end + local bars = assert(vbar._yline, "[InternalErr] no '_yline' field") + local bdim = #bars + if bdim == 0 then return "[InternalErr] number of bars is zero" end + if bdim % 2 ~= 0 then + return "[InternalErr] '_yline' does not have an even number of elements" + end + local data = self._data + data[#data + 1] = 36 -- vbar sequence start + data[#data + 1] = y1 + data[#data + 1] = y2 + data[#data + 1] = bdim / 2 -- the number of bars <x_i t_i> + for i = 1, bdim, 2 do + local coord = bars[i] + local width = bars[i + 1] + if type(coord) ~= "number" then + return "[Err] a coordinates is not a number" + end + if type(width) ~= "number" then + return "[Err] a width is not a number" + end + data[#data + 1] = coord + x0 + data[#data + 1] = width + end +end + +-- [text] <130> ax ay x y chars +function gaCanvas:encode_Text(txt, xpos, ypos, ax, ay) --> err + if type(txt) ~= "table" then + return "[ArgErr] 'txt' object table expected" + end + if type(xpos) ~= "number" then + return "[ArgErr] 'xpos' number expected" + end + if type(ypos) ~= "number" then + return "[ArgErr] 'ypos' number expected" + end + if ax == nil then + ax = 0 + elseif type(ax) ~= "number" then + return "[ArgErr] 'ax' number expected" + end + if ay == nil then + ay = 0 + elseif type(ay) ~= "number" then + return "[ArgErr] 'ay' number expected" + end + local data = self._data + data[#data + 1] = 130 + data[#data + 1] = ax -- relative anchor x-coordinate + data[#data + 1] = ay -- relative anchor y-coordinate + data[#data + 1] = xpos -- text x-coordinate + data[#data + 1] = ypos -- text y-coordinate + local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") + if #chars == 0 then return "[InternalErr] 'txt' has no chars" end + for _, c in ipairs(chars) do + data[#data + 1] = c + end + data[#data + 1] = 0 -- end string signal +end + +-- glyphs equally spaced along the baseline +-- [text_xspaced] <131> x1 xgap ay ypos chars +function gaCanvas:encode_Text_xspaced(txt, x1, xgap, ypos, ay) --> err + if type(txt)~= "table" then return "[ArgErr] 'txt' object table expected" end + local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") + if #chars == 0 then return "[InternalErr] 'txt' has no chars" end + if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end + if type(xgap) ~= "number" then return "[ArgErr] 'xgap' number expected" end + if xgap < 0 then + local n = #chars + x1 = x1 + (n - 1) * xgap + xgap = -xgap + end + if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end + if ay == nil then + ay = 0 + elseif type(ay) ~= "number" then + return "[ArgErr] 'ay' number expected" + end + local data = self._data + data[#data + 1] = 131 + data[#data + 1] = x1 -- x-coordinate of the first axis from left to right + data[#data + 1] = xgap -- axial distance among gliphs + data[#data + 1] = ay -- anchor relative y-coordinate + data[#data + 1] = ypos -- text y-coordinate + for _, c in ipairs(chars) do + data[#data + 1] = c + end + data[#data + 1] = 0 -- end string signal +end + +-- text_xwidth +-- text equally spaced but within [x1, x2] coordinate interval +-- <132> <ay: FLOAT> <x1: DIM> <x2: DIM> <y: DIM> <c: CHARS> +function gaCanvas:encode_Text_xwidth(txt, x1, x2, ypos, ay) --> err + if type(txt)~= "table" then return "[ArgErr] 'txt' object table expected" end + if type(x1) ~= "number" then return "[ArgErr] 'x1' number expected" end + if type(x2) ~= "number" then return "[ArgErr] 'x2' number expected" end + if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end + if ay == nil then + ay = 0 + elseif type(ay) ~= "number" then + return "[ArgErr] 'ay' number expected" + end + local chars = assert(txt.codepoint, "[InternalErr] no 'codepoint' field in txt") + if #chars == 0 then return "[InternalErr] 'txt' has no chars" end + if x1 > x2 then x1, x2 = x2, x1 end -- reorder coordinates + local data = self._data + data[#data + 1] = 132 + data[#data + 1] = ay -- anchor relative y-coordinate + data[#data + 1] = x1 -- left limit of the text box + data[#data + 1] = x2 -- right limit of the text box + data[#data + 1] = ypos -- text y-coordinate + for _, c in ipairs(chars) do + data[#data + 1] = c + end + data[#data + 1] = 0 -- end string signal +end + +-- experimental code section +-- new opcodes under assessment + +-- [start_text_group] 140 +function gaCanvas:start_text_group() --> err + local data = self._data + data[#data + 1] = 140 +end + +-- [gtext] 141 +function gaCanvas:gtext(chars) --> err + if type(chars) ~= "table" then return "[ArgErr] 'chars' table expected" end + local data = self._data + data[#data + 1] = 141 + for _, c in ipairs(chars) do + data[#data + 1] = c + end + data[#data + 1] = 0 -- end string signal +end + +-- [gtext_spaced] 142 gap string +function gaCanvas:gtext_spaced(gap, chars) --> err + if type(gap) ~= "number" then return "[ArgErr] 'gap' number expected" end + if type(chars) ~= "table" then return "[ArgErr] 'chars' table expected" end + local data = self._data + data[#data + 1] = 142 + data[#data + 1] = gap + for _, c in ipairs(chars) do + data[#data + 1] = c + end + data[#data + 1] = 0 -- end string signal +end + +-- [gtext_space] 143 gap +function gaCanvas:gtext_gap(gap) --> err + if type(gap) ~= "number" then return "[ArgErr] 'gap' number expected" end + local data = self._data + data[#data + 1] = 143 + data[#data + 1] = gap +end + + +-- [end_text_group] 149 ax ay x y +function gaCanvas:end_text_group(xpos, ypos, ax, ay) --> err + if type(xpos) ~= "number" then return "[ArgErr] 'xpos' number expected" end + if type(ypos) ~= "number" then return "[ArgErr] 'ypos' number expected" end + if type(ax) ~= "number" then return "[ArgErr] 'ax' number expected" end + if type(ay) ~= "number" then return "[ArgErr] 'ay' number expected" end + local data = self._data + data[#data + 1] = 149 + data[#data + 1] = ax -- anchor relative x-coordinate + data[#data + 1] = ay -- anchor relative y-coordinate + data[#data + 1] = xpos -- text x-coordinate + data[#data + 1] = ypos -- text y-coordinate +end + +-- amazing... +function gaCanvas:to_string() --> string + +end + +function gaCanvas:get_bbox() + +end + +function gaCanvas:check() --> boolean, err + +end + +return gaCanvas diff --git a/macros/luatex/generic/barracuda/lib/lib-geo/libgeo.lua b/macros/luatex/generic/barracuda/lib/lib-geo/libgeo.lua new file mode 100644 index 0000000000..fd53ca6509 --- /dev/null +++ b/macros/luatex/generic/barracuda/lib/lib-geo/libgeo.lua @@ -0,0 +1,289 @@ + +-- libgeo simple Geometric Library +-- Copyright (C) 2018 Roberto Giacomelli + +-- All dimension must be in scaled point (sp) + +local libgeo = { + _VERSION = "libgeo v0.0.3", + _NAME = "libgeo", + _DESCRIPTION = "simple geometric library", +} + +-- VBar class +-- a pure geometric entity of several infinite vertical lines +libgeo.Vbar = {} +local Vbar = libgeo.Vbar +Vbar.__index = Vbar + +-- Vbar costructors + +-- VBar costructor from an array [xcenter1, width1, xcenter2, width2, ...] +function Vbar:from_array(yl_arr) --> <vbar object> + assert(type(yl_arr) == "table", "'yline_array' is a mandatory arg") + -- stream scanning + local i = 1 + local xlim = 0.0 + while yl_arr[i] do + local x = yl_arr[i]; i = i + 1 + local w = yl_arr[i]; i = i + 1 + assert(type(x) == "number", "[InternalErr] not a number") + assert(type(w) == "number", "[InternalErr] not a number") + xlim = x + w/2 + end + assert(i % 2 == 0, "[InternalErr] the index is not even") + assert(i > 0, "[InternalErr] empty array") + local o = { + _yline = yl_arr, -- [<xcenter>, <width>, ...] flat array + _x_lim = xlim, -- right external bounding box coordinates + } + setmetatable(o, self) + return o +end + +-- costructor useful for Code128 encoder +-- from an integer: 21231 -> binary 11 0 11 000 1 -> symbol 110110001 +-- is_bar :: boolean :: bar or space as first element, default true +function Vbar:from_int(ngen, mod, is_bar) --> <vbar object> + assert(type(ngen) == "number", "Invalid argument for n") + assert(type(mod) == "number", "Invalid argument for module width") + if is_bar == nil then is_bar = true else + assert(type(is_bar) == "boolean", "Invalid argument for is_bar") + end + -- scan ngen for digits + local digits = {} + while ngen > 0 do + local d = ngen % 10 + digits[#digits + 1] = d + ngen = (ngen - d)/10 + end + local x0 = 0.0 -- axis reference + local yl = {} + for k = #digits, 1, -1 do + local d = digits[k] + local w = d*mod -- bar width + if is_bar then -- bar + yl[#yl + 1] = x0 + w/2 + yl[#yl + 1] = w + end + x0 = x0 + w + is_bar = not is_bar + end + local o = { + _yline = yl, -- [<xcenter>, <width>, ...] flat array + _x_lim = x0, -- right external coordinate + } + setmetatable(o, self) + return o +end + +-- from an integer to read from right to left +-- 13212 ->rev 21231 ->binary 11 0 11 000 1 -> symbol 110110001 +-- is_bar :: boolean :: bar or space for first, default true +function Vbar:from_int_revstep(ngen, mod, is_bar) --> <vbar object> + assert(type(ngen) == "number", "Invalid argument for n") + assert(type(mod) == "number", "Invalid argument for module width") + if is_bar == nil then is_bar = true else + assert(type(is_bar) == "boolean", "Invalid argument for is_bar") + end + -- + local x0 = 0.0 -- axis reference + local i = 0 + local yl = {} + while ngen > 0 do + local d = ngen % 10 -- first digit + local w = d*mod -- bar width + if is_bar then -- bar + i = i + 1; yl[i] = x0 + w/2 + i = i + 1; yl[i] = w + end + x0 = x0 + w + is_bar = not is_bar + ngen = (ngen - d)/10 + end + assert(not is_bar, "[InternalErr] the last element in not a bar") + local o = { + _yline = yl, -- [<xcenter>, <width>, ...] flat array + _x_lim = x0, -- right external coordinate + } + setmetatable(o, self) + return o +end + +-- costructor useful for Code39 encoder +-- i.e. 11212 -> rev -> 2 1 2 1 1 -> decodes to -> B w B w b +-- build a yline array from the integer definition. Digit decoding rule: +-- mod: b or w => 1 -- narrow bar/space +-- MOD: B or W => 2 -- wide bar/space +-- is_bar: the first element is a bar not a space, default to true +function Vbar:from_int_revpair(ngen, mod, MOD, is_bar) --> <vbar object> + assert(type(ngen) == "number", "Invalid argument for n") + assert(type(mod) == "number", "Invalid argument for narrow module width") + assert(type(MOD) == "number", "Invalid argument for wide module width") + assert(mod < MOD, "Not ordered narrow/Wide values") + if is_bar == nil then + is_bar = true + else + assert(type(is_bar) == "boolean", "Invalid argument for 'is_bar'") + end + local yl = {} + local x0 = 0.0 + local k = 0 + while ngen > 0 do + local d = ngen % 10 -- digit + ngen = (ngen - d)/10 + local w; if d == 1 then + w = mod + elseif d == 2 then + w = MOD + end; assert(w, "[InternalErr] Allowed digits are only 1 or 2") + if is_bar then -- bars + k = k + 1; yl[k] = x0 + w/2 -- xcenter + k = k + 1; yl[k] = w -- width + end + is_bar = not is_bar + x0 = x0 + w + end + assert(not is_bar, "[InternalErr] the last element is not a bar") + local o = { + _yline = yl, -- [<xcenter>, <width>, ...] flat array + _x_lim = x0, -- external x coordinate + } + setmetatable(o, self) + return o +end + +-- return a Vbar inteleaving to sequence narrow/Wide +-- tbar, tspace = {boolean sequence}, true -> narrow, false -> Wide +function Vbar:from_two_tab(tbar, tspace, mod, MOD) --> <vbar object> + assert(type(tbar) == "table", "tbar must be a table") + assert(type(tspace) == "table", "tspace must be a table") + assert(#tbar == #tspace, "tbar and tspace must be longer the same") + assert(type(mod) == "number", "Invalid argument for narrow module width") + assert(type(MOD) == "number", "Invalid argument for wide module width") + assert(mod < MOD, "Not ordered narrow/Wide values") + local x0 = 0.0 -- x-coordinate + local yl = {} + for i = 1, #tbar do + local is_narrow = tbar[i] + assert(type(is_narrow) == "boolean", "[InternalErr] found a not boolean value") + if is_narrow then + yl[#yl + 1] = x0 + mod/2 -- bar x-coordinate + yl[#yl + 1] = mod -- bar width + x0 = x0 + mod + else + yl[#yl + 1] = x0 + MOD/2 -- bar x-coordinate + yl[#yl + 1] = MOD -- bar width + x0 = x0 + MOD + end + local is_narrow_space = tspace[i] + assert(type(is_narrow_space) == "boolean", "[InternalErr] found a not boolean value") + if is_narrow_space then + x0 = x0 + mod + else + x0 = x0 + MOD + end + end + local o = { + _yline = yl, -- [<xcenter>, <width>, ...] flat array + _x_lim = x0, -- external x coordinate + } + setmetatable(o, self) + return o +end + +-- Text class + +libgeo.Text = {} +local Text = libgeo.Text +Text.__index = Text + +-- costructors +-- internally it keeps text as a sequence of codepoint +function Text:from_string(s) --> object + assert(type(s) == "string", "[ArgErr] 's' not a valid string") + assert(#s > 0, "[Err] 's' empty string not allowed") + + local cp = {} -- codepoint array + for b in string.gmatch(s, ".") do + cp[#cp + 1] = string.byte(b) + end + local o = { + codepoint = cp, + } + setmetatable(o, self) + return o +end + +-- arr, array of single digit number +-- i start index +-- j stop index +function Text:from_digit_array(arr, i, j) --> object + assert(type(arr) == "table", "[ArgErr] 'arr' not a table") + assert(#arr > 0, "[ArgErr] 'arr' is an empty array") + local cp = {} -- codepoint array + if i ~= nil then + assert(type(i) == "number", "[ArgErr] 'i' is not a number") + else + i = 1 + end + if j ~= nil then + assert(type(j) == "number", "[ArgErr] 'j' is not a number") + assert(i <= j, "[ArgErr] not suitable pair of array index") + else + j = #arr + end + for k = i, j do + local d = arr[k] + assert(type(d) == "number", "[ArgErr] array contains a not number element") + assert(d == math.floor(d), "[ArgErr] array contains a not integer number") + assert(d >= 0 or d < 10, "[ArgErr] array contains a not single digit number") + cp[#cp + 1] = d + 48 + end + local o = { + codepoint = cp, + } + setmetatable(o, self) + return o +end + + +-- from an array of chars +function Text:from_chars(chars) --> object + assert(type(chars) == "table", "[ArgErr] 'chars' must be a table") + local arr = {} + for _, c in ipairs(chars) do + arr[#arr + 1] = string.byte(c) + end + local o = { + codepoint = arr, + } + setmetatable(o, self) + return o +end + +-- provide an integer to build a Text object +function Text:from_int(n) --> object + assert(type(n) == "number", "[ArgErr] 'n' must be a number") + assert( n > 0, "[Err] 'n' must be positive") + assert( n == math.floor(n), "[Err] 'n' must be an integer") + local cp = {} + while n > 0 do + local d = n % 10 + cp[#cp + 1] = d + 48 + n = (n - d)/10 + end + local digits = #cp + for i = 1, digits/2 do -- reverse the array + local d = cp[digits - i + 1] + cp[digits - i + 1] = cp[i] + cp[i] = d + end + local o = { + codepoint = cp, + } + setmetatable(o, self) + return o +end + +return libgeo |