% \iffalse % Copyright(c) 2001 by David Kastrup % Any use of the code is permitted as long as this copyright notice is % preserved in the code. % % In case of an emergency (no LaTeX available), you may rename this % file to binhex.tex. In all other cases, use the accompanying % binhex.ins in order to extract binhex.drv (run LaTeX on it for % getting the documentation) and binhex.tex. If binhex.ins is % missing, you can regenerate it by running docstrip on this file with % the option ``installer'' set. % \fi % \CheckSum{251} % \title{The \texttt{binhex.tex} package for expansible conversion % into binary-based number systems} % \author{David Kastrup\thanks % {David.Kastrup@neuroinformatik.ruhr-uni-bochum.de}} % \maketitle % \tableofcontents % % \section{Usage} % This is a file for expandably converting numbers into binary, octal % and hexadecimal. All constructs \TeX\ accepts as an argument to its % |\number| primitive are valid. This holds for all numeric arguments % of the macros presented in here. % % You use this package by simply inputting it with % \begin{verbatim} %\input binhex % \end{verbatim} % It will work equally well under \LaTeX\ and plain \TeX. It does not % even use plain \TeX, but only \TeX\ primitives. Simply setting the % correct |\catcode| values for |{}#| and end of line will make it % load and work under ini\TeX. % % The following macros are defined: % \DescribeMacro{\binary} % |\binary{|\meta{number}|}| will convert \meta{number} into its binary % representation. % \samples\binary{0}{\maxdimen}{-"7EE6}. % % \DescribeMacro{\nbinary} % |\nbinary{|\meta{size}|}{|\meta{number}|}| will convert \meta{number} % into a binary representation of at least \meta{size} digits length, % filling up with leading zeros where necessary. The |-| sign of % negative numbers is not counted. If both \meta{size} and % \meta{number} are zero, an empty string is generated. This should % please some computer scientists in some situations. % \samples{\nbinary{3}}{3}{-2}{-12}. % % \DescribeMacro{\hex} % |\hex{|\meta{number}|}| converts \meta{number} into its hexadecimal % representation, using uppercase letters. % \samples\hex{34}{-4711}. % % \DescribeMacro{\nhex} % |\nhex{|\meta{size}|}{|\meta{number}|}| will convert \meta{number} % into a hexadecimal representation of at least \meta{size} digits length, % filling up with leading zeros where necessary. The |-| sign of % negative numbers is not counted. If both \meta{size} and % \meta{number} are zero, an empty string is generated. This should % please some computer scientists in some situations. % \samples{\nhex{3}}{3}{-\maxdimen}. % % \DescribeMacro{\oct} % |\oct{|\meta{number}|}| converts \meta{number} into its octal % representation. % \samples\oct{34}{-4711}. % % \DescribeMacro{\noct} % |\noct{|\meta{size}|}{|\meta{number}|}| will do the right thing. % \samples{\noct{3}}{13}{-\maxdimen}. % % \DescribeMacro{\tetra} % |\tetra{|\meta{number}|}| is for people counting with arms and legs % instead of fingers, or for quadrupeds. % \samples\tetra{34}{-4711}. % % \DescribeMacro{\ntetra} % |\ntetra{|\meta{size}|}{|\meta{number}|}| is for those of the same % count which have minimum requirements. % \samples{\ntetra{3}}{3}{-\maxdimen}. % % \DescribeMacro{\nbinbased} % |\nbinbased{|\meta{logbase}|}{|\meta{size}|}{|\meta{number}|}| will % convert \meta{number} into number base $2^{\text{\meta{logbase}}}$ and % generate at least \meta{size} digits. Only supported values of % \meta{logbase} are 1, 2, 3, 4. This is called by all other macros % except of the faster binary conversion macros. % \samples{\nbinbased{3}{3}}{13}{-\maxdimen}. % \samples{\nbinbased{2}{4}}{13}{-\maxdimen}. % % That's it, have fun! % \StopEventually{} % \section{Implementation} % Now the implementation. First save catcode of |@| and old contents of % |\toks0| in |\toks0|, then make |@| a letter to enable internal % macros. % \begin{macrocode} %<*style> \edef\next{\toks0=% {\catcode`\noexpand\@=\the\catcode`\@\toks0{\the\toks0}}% } \next \catcode`\@11 % \end{macrocode} % % \subsection{Binary conversions} % \subsubsection{Basics} % \begin{macro}{\bb@00} % \begin{macro}{\bb@01} % \begin{macro}{...} % \begin{macro}{\bb@19} % We now define the work horse macros for conversion of binary % commands. If numbers were allowed in macro names, one of those % definitions would be % \begin{verbatim} %\def\bb@13#1{6\csname bb@1#1\endcsname} % \end{verbatim} % That is, the macro divides the decimal two-digit number (up to~19) % embedded into its name by~2, spews out the result and starts up the % next macro with the first digit of the name of \emph{that} being the % remainder from its own division, and the second digit being the next % following one. % \begin{macrocode} \def\next#1#2#3{\expandafter \def \csname bb@#1\endcsname##1% {#2\csname bb@#3##1\endcsname}} \next{00}00 \next{01}01 \next{02}10 \next{03}11 \next{04}20 \next{05}21 \next{06}30 \next{07}31 \next{08}40 \next{09}41 \next{10}50 \next{11}51 \next{12}60 \next{13}61 \next{14}70 \next{15}71 \next{16}80 \next{17}81 \next{18}90 \next{19}91 % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\bb@0+} % \begin{macro}{\bb@1+} % Now we need to end such a conversion. For no particular reason at % all (well, some sneakiness might explain it later), we use |+| as an % end marker for the decimal digits. After the |+|, we collect the % resulting binary digits, from last to first. So here are two macros % to deal with the last digit produced. Simply tacks them on after % replacing the gobbled |+|. % \begin{macrocode} \expandafter \def \csname bb@0+\endcsname {+0} \expandafter \def \csname bb@1+\endcsname {+1} % \end{macrocode} % \end{macro} % \end{macro} % % Now all that remains to be done is to initiate the process, and to % end it again. The process ends when the decimal number reaches~0. % Since we want to produce one digit even when starting out, and we % check the end of recursion by comparing the result with~|0|, we have a % problem here. We solve it by comparing two letters, and looking for % the complete |0+| sequence, and we start out by prepending a trivial |0| % before the number to convert, so that at the first run it will be |00| % instead of |0| if the number in question is~0. % % \begin{macro}{(\binary)} % \begin{macro}{(\bb@dobinary)} % Actually, this is how we \emph{could} do things. The actual, slightly % different version used can be shared by the other converters, but % we'll keep this listed for reference. % \begin{verbatim} %\def\binary#1{\expandafter \bb@dobinary \expandafter 0\number#1+} %\def\bb@dobinary#1#2{\if0#1\if+#2\bb@endbinary \fi\fi % \expandafter \bb@dobinary \number \csname bb@0#1\endcsname #2} % \end{verbatim} % Notice that |\number| here serves multiple purposes. It will % initiate expansion that will only be stopped once the macros % generating the next binary digit will crank out a space or anything % else stopping expansion. Its second purpose is to get rid of any % leading zeros that might remain from the last loop through. % % \begin{macro}{\bb@endbinary} % |\bb@endbinary| can % be used as written, though. It scraps everything up to the tack % mark |+|, leaving only the converted results accumulated behind % that. Since this means scrapping |\fi\fi| as well, it reinserts % it in order to properly finish the conditional. % \begin{macrocode} \def\bb@endbinary#1+{\fi\fi} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsubsection{Negative numbers} % We would like negative numbers to work, too. The semantics for % defined field widths are unclear (so we basically just tack a |-| on % and convert the remaining number to the full width). Since the sign % of the number is easy to discern, further massaging of the number to % replace leading zeros by spaces, insert |+| signs and similar folderol % are easy to do and left as an exercise to the reader. We mostly % implement this to have the conversion not fail on any number. % % \begin{macro}{\bb@0-} % The following one-liner achieves that. Figure out why. It is easy. % \begin{macrocode} \expandafter \def \csname bb@0-\endcsname {0+-\bb@dobinary} % \end{macrocode} % \end{macro} % % \subsubsection{Minimum field widths} % \begin{macro}{\bb@0m} % \begin{macro}{\bb@1m} % We often have the situation that we want to produce a number that is % at least of a certain length. We specify this by tagging on an % appropriate number of |m| characters to the decimal as sort of a % format string. If we match such an~|m| at the end of the conversion, % we produce a digit and remove one~|m|, leaving all other |m| intact (or % whatever else happens to be before our |+| sign). % \begin{macrocode} \expandafter\def\csname bb@0m\endcsname#1+{#1+0} \expandafter\def\csname bb@1m\endcsname#1+{#1+1} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{(\nbinary)} % We call |\nbinary| with the number of digits as first argument, the number % itself as second. % % This now becomes trivial: % \begin{verbatim} %\def \nbinary#1#2{% % \binary{\number #2\romannumeral \number \number #1 000}% %} % \end{verbatim} % % Whoa, what about all these calls of |\number|? First notice the space % after |#1|. We need that in case |#1| happens to be octal or whatever, % since the |000| at the end is supposed to multiply by 1000 \emph{decimal}. % If |#1| were something like |'13| (11 decimal), the last |\number| will % expand |'13|, the |\number| before that will remove the blank we % inserted in case it was not needed to finish the number of digits, % we multiply by~1000 and turn this into a roman numeral consisting of % the appropriate amount of |m| letters. The very first |\number| ensures % that in case |#2| is a complete number without the need of trailing % spaces, still |\romannumeral| will be expanded when |\binary| first sets % sight on the whole thing. % \end{macro} % % \begin{macro}{\nbinary} % \begin{macro}{\binary} % \begin{macro}{\bb@dobinary} % Actually, since there is a certain logic to returning % an empty string when 0 is to be converted into a number at least 0 % characters long, we redefine the stuff the other way round, |\binary| % as a special case of |\nbinary|. We check the end by testing against % |0| followed by anything but~|m|. This has reasons\dots % % \begin{macrocode} \def\bb@dobinary#1#2{\if#10\if m\string#2\else\bb@endbinary\fi\fi \expandafter\bb@dobinary\number\csname bb@0#1\endcsname#2} \def\nbinary#1#2{\expandafter\bb@dobinary\number\number#2% \romannumeral\number\number#1 000+} \def\binary{\nbinary1} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Hexadecimal and the rest} % % Ok, stop with the small fry. Now we want to convert into % hexadecimal and octal as well. We do this by first converting into % binary, then into the wanted base whenever enough binary digits have % accumulated. In the following, we will talk about hex digits % exclusively for simplicity, even though they might indeed be octal % instead. % % \begin{macro}{\bb@h0} % \begin{macro}{\bb@h1} % \begin{macro}{\bb@h10} % \begin{macro}{...} % \begin{macro}{\bb@h1111} % % The following defines the equivalents of % \begin{verbatim} %\def \bb@h110#1+{\bb@dohex #1+6} % \end{verbatim} % This is a macro that appends 6, the representation of the binary % number in its name, after the tack mark |+|. So what's with the % |\number+|? Actually, here it does nothing but disappear. We just % write this to remind us of how the macros will be called. When the % macros are called, we use the same construct, and then |\number| % will disappear together with the~|+| (that we use as a tack mark) % and take along any leading zeros. We drop leading zeros so that we % can share the conversion macros for hex and octal (and quaternary?) % where they overlap. % % \begin{macrocode} \def \next #1#2{\expandafter \def \csname bb@h\number +#1\endcsname ##1+{\bb@dohex ##1+#2}% } \next {0}0 \next {1}1 \next {10}2 \next {11}3 \next {100}4 \next {101}5 \next {110}6 \next {111}7 \next{1000}8 \next{1001}9 \next{1010}A \next{1011}B \next{1100}C \next{1101}D \next{1110}E \next{1111}F % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\bb@dohex} % |\bb@dohex| is the magic macro that initiates accumulation of enough % binary digits for one hexadecimal one. It is called in % the following form: % \begin{quote} % |\bb@dohex| \meta{m\{\#rhex\}} |\endcsname| \meta{m\{\#bin\}} |+| % \end{quote} % Where |+| is the tack after which hex digits will accumulate, % \meta{m\{\#rhex\}} is a sequence of |m|, one for every remaining hex % digit we want to force out (same convention as with |\nbinary| above), % and \meta{m\{\#bin\}} is a sequence of |m| corresponding in length to % the number of binary digits we need to accumulate for one hexadecimal % (or octal) digit. % \begin{macrocode} \def\bb@dohex #1{\csname bb@x#1\endcsname} % \end{macrocode} % % Eeek! What is that? Ok, let's split it into the two cases, one with % forced digits remaining, one without any remaining forced digits. % If no forced digits remain, we get % \begin{quote} % |\bb@x \endcsname \endcsname| \meta{m\{\#bin\}} % \end{quote} % \end{macro} % % \begin{macro}{\bb@x} % |\bb@x| is defined as % \begin{macrocode} \def\bb@x\endcsname#1{ \bb@xm{m\endcsname}} % \end{macrocode} % % Notice the space at the start of the macro! It will stop % expansion. Furthermore, the |\endcsname| that |\bb@dohex| inserted is % scrapped, as well as the first |m| from % \meta{m\{\#bin\}}.\footnote{Why do we match |\string\endcsname| explicitly % for scrapping? The answer is debugging. We know it should always % be |\string\endcsname|, so let \TeX\ assert that it is indeed so. But we % also know that the next character will be |m|, why don't we match % \emph{that} explicitly? The answer is that we cannot be sure about the % |\string\catcode| of the matched~|m|. A hand-entered |m| has % |\string\catcode|~11, a \TeX-generated one (with |\string\string| or % |\string\romannumeral| or such) has |\string\catcode|~12. You'll % find that all the code here has been carefully % designed so that it will not care which it gets, so we don't make % an exception here. % } % \end{macro} % % \begin{macro}{\bb@xm} % The argument fed to |\bb@xm| is part of some jiggery-pokery we want % to happen when |\bb@dobinary| resumes expansion. First, however, it % will take a look and decide whether it will stop generating digits % altogether. As |\string \bb@xm| does not start with |m|, |\bb@dobinary| % will stop expansion when the decimal to convert has shrunk to 0. % Fine. Now what does |\bb@xm| do? % \begin{macrocode} \def\bb@xm #1\endcsname #2#3+{#2#3% \csname bb@h\number+\endcsname #1\endcsname m#3+} % \end{macrocode} % \end{macro} % % This is rather straightforward for the case of forced digits: the % number of binary digits is encoded in the form of \meta{m\{\#bin\}} in % |#2#3|. After the conversion of those digits, the appropriate hex % digit macro is called and sets up |\bb@dohex| again for the next hex % digit. Piece of cake. Now what happens in the case we have resumed % from |\do@binary| having had its option of stopping expansion? % % In that case, we get called with the next \meta{digit} % already arriving. This looks more or less like % \begin{quote} % |\csname bb@|\meta{digit}|\bb@xm \endcsname{m\endcsname}| % \meta{m\{\#bin-1\}} % \end{quote} % See what happens? This expands |\bb@xm|, after which a command of the % name |\bb@|\meta{digit}|m| (\meta{digit} being 0 or~1) gets executed. % It stashes away \meta{digit} after % the conveniently provided |+| sign, and \meta{\#bin-1} digits remain for % conversion. % % You think this contrived? Well, buster, let me tell you that the % previous version was way more insane. Have it still in RCS. % % \begin{macro}{\bb@nbinbased} % The following macro needs to get |#1|, the decimal number to convert, % in text form already. This is so that |\number#1| will continue % expanding after |#1|, expanding |\bb@dohex| exactly once. This problem % does not exist for the |\romannumeral| calls for |#2| and |#3|, so % spurious expansion with |\number\number| does no harm, since it is % stopped readily at the hard |\endcsname| and |+| thresholds. % \begin{macrocode} \def\bb@nbinbased #1#2#3{\expandafter \bb@dobinary \number#1% \expandafter \bb@dohex \romannumeral \number\number #2 000\expandafter\endcsname \romannumeral \number\number #3 000+} % \end{macrocode} % \end{macro} % % \begin{macro}{\nbinbased} % The following macro gets 3~arguments, the number of binary digits the % output digits shall be based on, the number of digits to produce at % least, and the number itself. It expands the number into text % form. If the number is not space-terminated, the closing brace % reliably stops expansion nevertheless, so that |\bb@nbinbased| gets a % clean number. % \begin{macrocode} \def\nbinbased #1#2#3{\expandafter\bb@nbinbased \expandafter {\number#3}{#2}{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{\nhex} % \begin{macro}{\noct} % \begin{macro}{\ntetra} % \begin{macro}{\hex} % \begin{macro}{\oct} % \begin{macro}{\tetra} % Now follow the obvious definitions: % \begin{macrocode} \def\nhex{\nbinbased4} \def\noct{\nbinbased3} \def\ntetra{\nbinbased2} \def\hex{\nhex1} \def\oct{\noct1} \def\tetra{\ntetra1} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \subsection{The end} % Restore |\catcode`\@| and |\toks0| and finish. % \begin{macrocode} \the\toks0 % % \end{macrocode} % And that was that! % \section{Various drivers} % The installer, in case it is missing. % \begin{macrocode} % \input docstrip % \generate{ % \file{binhex.drv}{\from{binhex.dtx}{driver}} % \usedir{tex/generic/misc} % \file{binhex.tex}{\from{binhex.dtx}{style}} % } % \endbatchfile % \end{macrocode} % And here comes the documentation driver. % \begin{macrocode} % \documentclass{ltxdoc} % \usepackage{amsmath} % \input binhex.tex % \end{macrocode} % \begin{macro}{\verbatize} % |\detokenize| is available in e\TeX, but we may not have that\dots % The |\fontdimen| folderol makes spaces temporarily disabled. Looks % prettier. Sorry for that. % \begin{macrocode} % \def\verbatize#1{\begingroup % \toks0{#1}\edef\next{\the\toks0}% % \dimen0\the\fontdimen2\font % \fontdimen2\font=0pt % \expandafter\stripit % \meaning\next % \fontdimen2\font=\dimen0 % \endgroup} % \def\next{} % \expandafter\def\expandafter\stripit\meaning\next{} % \end{macrocode} % \end{macro} % \begin{macro}{\showeffect} % |\showeffect|\meta{Stuff} will put out a one-line correspondence of % the verbatim source of \meta{Stuff} with its expansion, to be used % in a |aligned| environment or similar. % \begin{macrocode} % \newcommand\showeffect[1]{% % \text{\verbatize{#1}}\quad&\rightarrow\quad\text{#1}% % \\} % \end{macrocode} % \end{macro} % \begin{macro}{\samples} % |\samples| gets one parameter, and a following expression list ended % by a period. It applies that parameter to each of the expressions % in the list and generates a correspondance table for each. For % example, % \begin{verbatim} %\samples{\nbinary{3}}{3}{-2}{-12}. % \end{verbatim} % was used in this document to produce % \samples{\nbinary{3}}{3}{-2}{-12}. % \begin{macrocode} % \def\samples{\begingroup\MacroFont\[\begin{aligned}\nextsample} % \def\nextsample#1#2{% % \if.\noexpand#2\expandafter\endsamples\fi % \showeffect{#1{#2}}\nextsample{#1}} % \def\endsamples#1\nextsample#2{\end{aligned}\]\endgroup} % \end{macrocode} % \end{macro} % Now all that remains is inputting the stuff. % \begin{macrocode} % \begin{document} % \DocInput{binhex.dtx} % \end{document} % \end{macrocode} % \Finale{}