% \iffalse % vim: set expandtab: % vim: set shiftwidth=2: % vim: set tabstop=2: % \fi % \iffalse meta-comment % % Copyright (C) 2026 by Lukas Heindl % --------------------------------------------------------------------------- % 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-parser.dtx} % %\NeedsTeXFormat{LaTeX2e}[2022-06-01] % %<*driver> \begin{document} \DocInput{\jobname.dtx} \PrintChanges \PrintIndex \end{document} % % \changes{v0.0.0}{2026-05-14}{First draft} % % % \fi % % \iffalse %<*package> %<@@=hexdumptikz_parser> % \fi % % \maketitle % % \begin{abstract} % General variables and helpers for parsing hexdump data from file. % Also includes some documentation about the general parsing architcture. % \end{abstract} % % Generally, the idea is as follows. % The user (indirectly) calls the respective parser and passes a callback along. % This callback is then responsible for drawing a line of the hexdump. % % \subsection{Interfaces} % Callback: % \begin{args} % 1 & \ain & line-index \\ % 2 & \ain & parsed offset/address \\ % 3 & \ain & parsed bytes (seq) \\ % 4 & \aout & variable to signal whether printing / the selection has finished \\ % \end{args} % % Parser: % \begin{args} % 1 & \ain & filename which shall be parsed \\ % 2 & \ain & callback \\ % \end{args} % % \subsection{Implementation} % % Identify the package and give the over all version information. % \begin{macrocode} \ProvidesExplPackage {hexdumptikz-parser} {2026-06-20} {1.0.1} {Printing and annotating hexdumps with TikZ} \RequirePackage { hexdumptikz-parser-hd } % \end{macrocode} % \begin{var}{\l_hexdumptikz_parser_ior} % IO variable for opening the file % \begin{macrocode} \ior_new:N \l_hexdumptikz_parser_ior % \end{macrocode} % \end{var} % \begin{var}{\l_hexdumptikz_parser_line_int} % Counter for the lines in the input % \begin{macrocode} \int_new:N \l_hexdumptikz_parser_line_int % \end{macrocode} % \end{var} % % \begin{var}{\l_hexdumptikz_parser_offset_tl} % Parsed offset / the address % \begin{macrocode} \tl_new:N \l_hexdumptikz_parser_offset_tl % \end{macrocode} % \end{var} % \begin{var}{\l_hexdumptikz_parser_line_tl} % Complete parsed line % \begin{macrocode} \tl_new:N \l_hexdumptikz_parser_line_tl % \end{macrocode} % \end{var} % % \begin{var}{\l_hexdumptikz_parser_bytes_seq} % Sequence of the parsed bytes % \begin{macrocode} \seq_new:N \l_hexdumptikz_parser_bytes_seq % \end{macrocode} % \end{var} % \begin{var}{\l_hexdumptikz_parser_last_line_seen_bool} % Whether the parser assumes the last line has already been processed (might be useful for some stricter input validation tests) % \begin{macrocode} \bool_new:N \l_hexdumptikz_parser_last_line_seen_bool % \end{macrocode} % \end{var} % \begin{var}{\l_hexdumptikz_parser_finished_bool} % Variable which is passed to the callback as notification channel in the other direction % \begin{macrocode} \bool_new:N \l_hexdumptikz_parser_finished_bool % \end{macrocode} % \end{var} % % Variables configuring the parsers. % \begin{var}{\l_hexdumptikz_parser_strict_byte_num_bool} % Whether the number of bytes should be checked and an error being raised if there is a missmatch with the expected number. % \begin{macrocode} \bool_new:N \l_hexdumptikz_parser_strict_byte_num_bool % \end{macrocode} % \end{var} % \begin{var}{\l_hexdumptikz_parser_strict_hex_bool} % Whether to check for valid hex characters in the byte input. % \begin{macrocode} \bool_new:N \l_hexdumptikz_parser_strict_hex_bool % \end{macrocode} % \end{var} % \begin{var}{\l_hexdumptikz_parser_leading_base_bool} % Whether the value specification includes the base (\texttt{0x}) % \begin{macrocode} \bool_new:N \l_hexdumptikz_parser_leading_base_bool % \end{macrocode} % \end{var} % % \begin{fn}{\hexdumptikz_parser_parse:nN} % An alias to the active parser. % \begin{macrocode} \cs_new_eq:NN \hexdumptikz_parser_parse:nN \hexdumptikz_parser_hd:nN % \end{macrocode} % \end{fn} % % % \begin{macrocode} \cs_generate_variant:Nn \str_range_ignore_spaces:nnn { Vnn } % \end{macrocode} % % % \begin{var}{\c_hexdumptikz_parser_addr_regex} % Matches an address specifier with an optional leading \texttt{0x} and an optional trailing \texttt{:}. % Extracts the raw address in its first capturing group. % \begin{macrocode} \regex_const:Nn \c_hexdumptikz_parser_addr_regex { \A \s* (?:0x)? ([0-9A-Fa-f]+) \s* :? \s* } % \end{macrocode} % \end{var} % \begin{var}{\c_hexdumptikz_parser_leading_hex_byte_regex} % Matches a byte in its hexadecimal representation (2 hex-digits). % \begin{macrocode} \regex_const:Nn \c_hexdumptikz_parser_leading_hex_byte_regex { \A [0-9A-Fa-f] { 2 } } % \end{macrocode} % \end{var} % % \subsubsection{Pgfkeys} % \begin{pgfkey}{parser} % \begin{macrocode} \pgfkeys { /hexdumptikz, parser/.is~choice, parser/hd/.code = { \cs_set_eq:NN \hexdumptikz_parser_parse:nN \hexdumptikz_parser_hd:nN } } % \end{macrocode} % \end{pgfkey} % % Define interface to simplify setting parser options. % \begin{macrocode} \pgfkeys { /hexdumptikz/parser~opts~hd/.code={ \pgfkeys{ /hexdumptikz/parser~opts/hd, #1 } }, } % \end{macrocode} % Define parser options % \begin{macrocode} \pgfkeys { /hexdumptikz/parser~opts/hd/.is~family, /hexdumptikz/parser~opts/hd, % \end{macrocode} % % \begin{pgfkey}{strict~byte~number~per~row} % \begin{macrocode} strict~byte~number~per~row/.code={ \hexdumptikz_common_parse_bool:Nn \l_hexdumptikz_parser_strict_byte_num_bool { #1 } }, strict~byte~number~per~row/.default={true}, % \end{macrocode} % \end{pgfkey} % % \begin{pgfkey}{strict~hex~digits} % \begin{macrocode} strict~hex~digits/.code={ \hexdumptikz_common_parse_bool:Nn \l_hexdumptikz_parser_strict_hex_bool { #1 } }, strict~hex~digits/.default={true}, % \end{macrocode} % \end{pgfkey} % % \begin{pgfkey}{leading~value~base} % \begin{macrocode} leading~value~base/.code={ \hexdumptikz_common_parse_bool:Nn \l_hexdumptikz_parser_leading_base_bool { #1 } }, leading~value~base/.default={true}, % \end{macrocode} % \end{pgfkey} % \begin{macrocode} } % \end{macrocode} % % \subsubsection{Errors} % \begin{error}{no-valid-offset} % \begin{macrocode} \msg_new:nnn { hexdumptikz-parser } { no-valid-offset } { No~valid~offset/address~found~in~line~'#1' } % \end{macrocode} % \end{error} % \begin{error}{too-many-bytes} % \begin{macrocode} \msg_new:nnn { hexdumptikz-parser } { too-many-bytes } { Line~with~offset~#1~has~more~than~#2~bytes.~Left~over~is:~#3 } % \end{macrocode} % \end{error} % \begin{error}{invalid-hex-digits} % \begin{macrocode} \msg_new:nnn { hexdumptikz-parser } { invalid-hex-digits } { The~next~bytes~on~the~following~line~are~no~valid~hex~bytes:~#1 } % \end{macrocode} % \end{error} % \begin{error}{weird-byte-count} % \begin{macrocode} \msg_new:nnn { hexdumptikz-parser } { weird-byte-count } { A~line~with~less~than~'bytes~per~row'~ (#1)~ bytes~is~only~allowed~as~last~line.~Line~at~offset:~#2 } % \end{macrocode} % \end{error} % \begin{error}{leading-base-missing} % \begin{macrocode} \msg_new:nnn { hexdumptikz-parser } { leading-base-missing } { Expected~leading~'0x'~missing~in~line~#1 } % \end{macrocode} % \end{error} % \iffalse % % \fi % % \Finale