summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/randtext/randtext.sty
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/randtext/randtext.sty
Initial commit
Diffstat (limited to 'macros/latex/contrib/randtext/randtext.sty')
-rw-r--r--macros/latex/contrib/randtext/randtext.sty143
1 files changed, 143 insertions, 0 deletions
diff --git a/macros/latex/contrib/randtext/randtext.sty b/macros/latex/contrib/randtext/randtext.sty
new file mode 100644
index 0000000000..0274642c87
--- /dev/null
+++ b/macros/latex/contrib/randtext/randtext.sty
@@ -0,0 +1,143 @@
+%
+% randtext.sty
+%
+% Charles Duan (2004/12/20)
+%
+% Provides one useful macro, \randomize{TEXT}. Result is a typeset box that
+% looks, on paper, like TEXT, but whose letters have in fact been placed in
+% random order so that they are not copiable from the file directly.
+%
+% In other words, typing:
+%
+% This is a \randomize{random-text} test.
+%
+% would produce output that looks like:
+%
+% This is a random-text test.
+%
+% but if you tried to copy-paste it from the output file, you would probably get
+%
+% This is a mdoxt-etnra test.
+%
+% The function of this odd macro is to obfuscate e-mail addresses, say on a PDF
+% document put online, so that the human reader sees the address as expected,
+% but e-mail address harvesters and spambots cannot determine the address. Since
+% this macro is done entirely using TeX typesetting commands, it requires no
+% external image generation or anything, and the typeset result is just as
+% high-quality as if no obfuscation had taken place.
+%
+% This macro does take into account kerning between character pairs, but it does
+% not account for ligatures. To make appropriate ligatures, surround the
+% ligature characters with braces.
+%
+% This package supersedes "switcheml.sty", written by the same author. (That is
+% the reason that the internal macros begin with "se@".
+%
+% Requires the file "random.tex", by Donald Arseneau. I believe that this file
+% comes as part of a standard TeX distribution.
+%
+%
+\ProvidesPackage{randtext}[2004/12/20 Obfuscate text]
+%
+% We use the random package to pick random numbers.
+\input random
+%
+% \se@count stores the number of letters/groups to typeset. For instance,
+% \randomize{abc{de}fg{hij}kl}
+% contains 9 letters/groups.
+\newcount\se@count
+%
+% \se@random is a random number register.
+\newcount\se@random
+%
+% \se@pos is used to store the width of each section of the randomized text.
+\newdimen\se@pos
+%
+% Randomize the text of the argument.
+\def\randomize#1{%
+ % Do nothing for empty argument.
+ \def\se@tmp{#1}\ifx\se@tmp\@empty\else
+ % Make our work local
+ \begingroup
+ % In case this is the first thing in the paragraph, go to horizontal
+ % mode
+ \leavevmode
+ % Initialize \se@count=1, \se@pos=0pt
+ \se@count\@ne
+ \se@pos\z@
+ % Now iterate over the argument text. The \relax is put at the end
+ % as an untypeset token.
+ \se@randomize#1\relax\@stop
+ \endgroup
+ \fi
+}
+%
+% Iterator function for \randomize. Essentially, this function will be executed
+% once for each token in the list.
+\def\se@randomize#1#2#3\@stop{%
+ % Define a macro \pos@[\se@count]. Essentially, this makes a unique,
+ % numbered macro for each letter/group.
+ \expandafter\edef\csname pos@\the\se@count\endcsname{%
+ % The macro produces a zero-width box that jumps forward \se@pos and
+ % then typesets the letter/group. Note the \the\se@pos, to force current
+ % evaluation of the distance to move forward.
+ \noexpand\rlap{\hskip\the\se@pos\relax#1}%
+ }%
+ % Advance \se@pos forward by the width of the first group and the
+ % immediately subsequent group, and then backward by the width of the second
+ % group. The effect is to advance \se@pos by the first group and the kern
+ % between the first and second groups.
+ \setbox\z@\hbox{#1#2}\advance\se@pos\wd\z@
+ \setbox\z@\hbox{#2}\advance\se@pos-\wd\z@
+ %
+ % If there's nothing left to iterate over, then:
+ % \se@pos is the width of the whole text
+ % \se@count is the number of letters/groups, or the highest \pos@[number]
+ % so we make a box of width \se@pos, place our random letters in it with
+ % \se@rand@place, and fill up the box for good measure.
+ %
+ % Otherwise, increment \se@count and run the function again.
+ %
+ % Note two things:
+ % 1. We put braces around #2 but not #3. Since there's an extra \relax at
+ % the end of #3 at all times, we don't have the problem of TeX stripping any
+ % braces from it.
+ % 2. The other reason we needed that \relax was that, since we read
+ % letters/groups in pairs, the last letter/group would only be read if there
+ % was an extra token at the end (i.e., the \relax).
+ \def\se@tmp{#3}\ifx\se@tmp\@empty \expandafter\@firstoftwo
+ \else \expandafter\@secondoftwo \fi
+ {\hb@xt@\se@pos{\se@rand@place\hfill}}%
+ {\advance\se@count\@ne\se@randomize{#2}#3\@stop}%
+}
+%
+% Now all of our \pos@[number] functions are set, and we just need to randomly
+% select and place.
+\def\se@rand@place{%
+ %
+ % Pick a random number between one and \se@num. (If \se@num>3, then ensure
+ % that the number is over three. This way, the first two elements will
+ % always be typeset last, guaranteeing at least some contortion.)
+ \ifnum\se@count>\z@
+ \ifnum\se@count>\thr@@
+ \setrannum\se@random\thr@@\se@count
+ \else
+ \setrannum\se@random\@ne\se@count
+ \fi
+ % Execute \pos@[\se@random].
+ \csname pos@\the\se@random\endcsname
+ % Now replace \pos@[\se@random] with \pos@[\se@count] and decrement
+ % \se@count. This way, the next random number will be guaranteed to
+ % typeset an unselected value.
+ \ifnum\se@random=\se@count\else
+ \edef\reserved@a{%
+ \let\expandafter\noexpand\csname pos@\the\se@random\endcsname
+ \expandafter\noexpand\csname pos@\the\se@count\endcsname
+ }\reserved@a
+ \fi
+ \advance\se@count\m@ne
+ % Repeat
+ \expandafter\se@rand@place
+ \fi
+}
+\endinput