% \iffalse
% vim: set expandtab:
% vim: set shiftwidth=2:
% vim: set tabstop=2:
% \fi
% \iffalse meta-comment
%
% Copyright (C) 2026 by Lukas Heindl <oss.heindl+latex@protonmail.com>
% ---------------------------------------------------------------------------
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008/05/04 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Lukas Heindl.
%
% This work consists of all files listed in manifest.txt.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{hexdumptikz-code.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}[2022-06-01]
%
%<*driver>
\documentclass{ltxdoc}
\usepackage[numbered]{hypdoc}

\usepackage{hexdumptikz}
\usepackage{csquotes}
\usepackage{xspace}
\usepackage{array}
\usepackage{amsmath}

\usepackage{tikz}
\usetikzlibrary{positioning,arrows.meta}
\tikzset{
	>={Stealth[scale=1.5]},
}

\NewDocumentEnvironment{sideeffects}{+b}{%
  \par
  \def\sclobber{\texttt{clobbered}\xspace}%
  \def\sdir{\texttt{  dir}\xspace}%
  \def\sindir{\texttt{indir}\xspace}%
  \noindent Sideeffects:\\
  \begin{tabular}{rrl}
    #1
  \end{tabular}
}{\par}

\NewDocumentEnvironment{args}{+b}{%
  \par
  \def\ain{\texttt{in}}%
  \def\aout{\texttt{out}}%
  \noindent Arguments:\\
  \begin{tabular}{>{\#}ccl}
    #1
  \end{tabular}
}{\par}

\def\MakePrivateLetters{%
   \makeatletter
   \catcode`\_11
   \catcode`\:11}

\NewDocElement[%
  macrolike,
  idxtype=fn.,
  idxgroup=expl3 functions,
  printtype=\textit{fn.},
]{Fn}{fn}
\NewDocElement[%
  macrolike,
  idxtype=var,
  idxgroup=expl3 variables,
  printtype=\textit{var.},
]{Var}{var}
\NewDocElement[%
  idxtype=pgfkey,
  idxgroup=pgfkeys,
  printtype=\textit{pgfkey},
]{Pgfkey}{pgfkey}
\NewDocElement[%
  idxtype=error,
  idxgroup=error,
  printtype=\textit{error},
]{Error}{error}

\EnableCrossrefs
\CodelineIndex
\RecordChanges

\setcounter{IndexColumns}{2}
\setlength\IndexMin{100pt} % see https://tex.stackexchange.com/questions/95882/avoid-multicol-error-error-saving-partial-page

\begin{document}
  \DocInput{\jobname.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%
% \changes{v0.0.0}{2026-05-14}{First draft}
%
%</driver>
% \fi
%
% \GetFileInfo{hexdumptikz.sty}
%
% \title{\textsf{hexdumptikz-code} -- \fileinfo}
% \author{Lukas Heindl\thanks{%
%     E-Mail: \href{oss.heindl+latex@protonmail.com}{oss.heindl+latex@protonmail.com}\\%
%     Issue tracker: \href{https://codeberg.org/atticus-sullivan/hexdumptikz/issues}{codeberg.org/atticus-sullivan/hexdumptikz/issues}\\%
%     Codeberg (mirror): \href{https://codeberg.org/atticus-sullivan/hexdumptikz}{codeberg.org/atticus-sullivan/hexdumptikz}\\%
%     \\%
% }}
% \date{\fileversion~from \filedate}
% \maketitle
% \iffalse
%<*package>
%<@@=hexdumptikz>
% \fi
%
% High-level overview of how the different modules / sub-packages work together:
%
% \begin{tikzpicture}[every node/.style={align=center,font=\sffamily}]
%   \node[]                       (user)       {User};
%   \node[right=of user]          (draw-hd)    {draw(-hd)};
%   \node[below right=of draw-hd] (parser)     {parser};
%   \node[above=of draw-hd]       (sel-row)    {selector\\row};
%   \node[above right=of draw-hd] (sel-sty)    {selector\\style};
%   \node[below=14ex of user]          (draw-label) {annotate};
%   %
%   \path[every edge/.style={->,draw}]
%   (user)    edge[]           node[above,sloped] {1}   (draw-hd)
%   (draw-hd) edge[bend left]  node[above,sloped] {2}   (parser)
%   (parser)  edge[bend left]  node[below,sloped] {3}   (draw-hd)
%   (draw-hd) edge[]           node[above,sloped] {4}   (sel-row)
%   (draw-hd) edge[]           node[above,sloped] {5}   (sel-sty)
%   (user)    edge[]           node[below,sloped] {(6)} node[above,sloped] {labeling} (draw-label)
%   ;
%   \node[rotate=45,anchor=south] at (parser.north west) {loop};
% \end{tikzpicture}
%
% \part{Implementation}
% \phantomsection
% \refstepcounter{section}
% \addcontentsline{toc}{section}{\mdseries\pkg{hexdumptikz}}%
%
% \makeatletter
% \let\origmaketitle\maketitle
% \NewDocumentCommand \pkginput {O{#2}m}{%
%   \begingroup
%     \def\maketitle{%
%       \GetFileInfo{hexdumptikz-#1.sty}
%       \ifx\@title\@empty
%         \def\@title{\pkg{hexdumptikz-#1}}%
%       \fi
%       \ifx\@author\@empty
%         \def\@author{Lukas Heindl}%
%       \fi
%       \def\@date{\fileversion~from \filedate}%
%       \let\saved@title\@title
%       \origmaketitle
%       \phantomsection
%       \refstepcounter{section}
%       \addcontentsline{toc}{section}{\mdseries\pkg{\saved@title}}%
%     }%
%     \let\Finale\relax
%     \let\PrintIndex\relax
%     \let\PrintChanges\relax
%     \input{hexdumptikz-#2.dtx}%
%   \endgroup
% }
% \makeatother
%
% Identify the package and give the over all version information.
%    \begin{macrocode}
\ProvidesExplPackage {hexdumptikz} {2026-06-16} {1.0.0}
  {Printing and annotating hexdumps with TikZ}
%    \end{macrocode}
%
% Load external dependencies
%    \begin{macrocode}
\RequirePackage { tikz }
\ExplSyntaxOff
\usetikzlibrary{chains}
\ExplSyntaxOn
%    \end{macrocode}
%
% Load internal (sub-)packages
%    \begin{macrocode}
\RequirePackage { hexdumptikz-common }
\RequirePackage { hexdumptikz-draw }
\RequirePackage { hexdumptikz-annotate }
\RequirePackage { hexdumptikz-addrcalc }
%    \end{macrocode}
%
%
% \subsection{Errors}
% \begin{error}{unknown-row}
%    \begin{macrocode}
\msg_new:nnn { hexdumptikz } { unknown-row }
  { The~(#2)~row~with~the~id~#1~is~unknown. }
%    \end{macrocode}
% \end{error}
%
% \begin{error}{invalid-address}
%    \begin{macrocode}
\msg_new:nnn { hexdumptikz } { invalid-address }
  { #1~is~not~a~valid~address. }
%    \end{macrocode}
% \end{error}
%
% \begin{error}{address-too-short}
%    \begin{macrocode}
\msg_new:nnn { hexdumptikz } { address-too-short }
  { Address~'#1'~is~too~short.~Must~be~at~least~#2~long. }
%    \end{macrocode}
% \end{error}
%
% \begin{error}{invalid-boolean}
%    \begin{macrocode}
\msg_new:nnn { hexdumptikz } { invalid-boolean }
  { '#1'~cannot~be~parsed~as~boolean. }
%    \end{macrocode}
% \end{error}
%
% \begin{error}{weird-num-bytes-per-row}
%    \begin{macrocode}
\msg_new:nnn { hexdumptikz } { weird-num-bytes-per-row }
  { '#1'~is~a~weird~num~bytes~per~row. }
%    \end{macrocode}
% \end{error}
%
% \subsection{Main/Public functions/Macros}
% \begin{fn}{\@@_begin:nn}
% Begin-code when a new hexdumptikz environment is started
% \begin{args}
%   1 & \ain & pgfkeys \\
%   2 & \ain & filename from which to read the hexdump from \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_begin:nn #1 #2 {
  \pgfkeys {
    /hexdumptikz,
    #1
  }
  \str_set:Ne \l_hexdumptikz_common_input_file_str { #2 }
  \begin { scope }[/hexdumptikz/next~scope]
    \pgfkeys { /hexdumptikz/next~scope/.style = { } }
}
%    \end{macrocode}
% \end{fn}
%
% \begin{fn}{\@@_end:}
% End-code when a hexdumptikz environment stops -- doing come cleanup
% \begin{args}
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Nn \@@_end: {
  \prop_gclear:N \g_hexdumptikz_common_cur_offsets_prop
  \end { scope }
}
%    \end{macrocode}
% \end{fn}
%
% \begin{environment}{hexdumptikz}
% Define an environment which wraps the hexdumptikz related operations.
% SHOULD be placed inside a tikz-environment. % TODO
%    \begin{macrocode}
\NewDocumentEnvironment { hexdumptikz } { O { } m }
{
  \@@_begin:nn { #1 } { #2 }
} {
  \@@_end:
}
%    \end{macrocode}
% \end{environment}
%
% \begin{macro}{\hexdumptikzPrint}
% Define a macro which prints the hexdump which was previously specified (via its filename).
% SHOULD be placed inside a hexdumptikz-environment % TODO
%    \begin{macrocode}
\NewDocumentCommand{ \hexdumptikzPrint } { O { } m }
{
  \hexdumptikz_draw_print:nn { #1 } { #2 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\hexdumptikzLabelBytes}
% Define a macro which labels a sequence of bytes in the printed hexdump.
% SHOULD be placed inside a hexdumptikz-environment % TODO
% Should be placed after the hexdump was printed.
%    \begin{macrocode}
\NewDocumentCommand{ \hexdumptikzLabelBytes } { O { } mm }
{
  \__hexdumptikz_annotate_label_bytes:nnn { #1 } { #2 } { #3 }
}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\hexdumptikzLabelBytesFallback}
% Define a macro which labels a sequence of bytes in the printed hexdump.
% Also works without the data gathered while printing the dump (outside of the environment).
% But the output does look a little bit less good compared to the normal annotation.
%    \begin{macrocode}
\NewDocumentCommand{ \hexdumptikzLabelBytesFallback } { O { } mm }
{
  \__hexdumptikz_annotate_label_bytes_fallback:nnn { #1 } { #2 } { #3 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\hexdumptikzAddrToNodename}
% Define a helper macro which converts a full address to its nodename in the hexdump.
% Can be used by the user for custom drawings.
%    \begin{macrocode}
\NewDocumentCommand{ \hexdumptikzAddrToNodename } { m }
{
  \__hexdumptikz_addrcalc_address_to_nodename:e { #1 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\hexdumptikzAddrToRow}
% Define a helper macro which converts a full address to the row in which the byte is placed.
% Can be used by the user for custom drawings.
%    \begin{macrocode}
\NewDocumentCommand{ \hexdumptikzAddrToRow } { m }
{
  \__hexdumptikz_addrcalc_address_to_row:e { #1 }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\hexdumptikzAddrToCol}
% Define a helper macro which converts a full address to the column in which the byte is placed.
% Can be used by the user for custom drawings.
%    \begin{macrocode}
\NewDocumentCommand{ \hexdumptikzAddrToCol } { m }
{
  \__hexdumptikz_addrcalc_address_to_col:e { #1 }
}
%    \end{macrocode}
% \end{macro}
%
% \pkginput{common}
% \pkginput{draw}
% \pkginput{addrcalc}
% \pkginput{annotate}
% \pkginput{parser}
% \pkginput{parser-hd}
% \pkginput{selector}
% \pkginput{selector-parser}
% \pkginput{selector-matcher}
%
% \iffalse
%</package>
% \fi
%
% \Finale
