summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/dvisirule/dvisirule.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/dvisirule/dvisirule.dtx')
-rw-r--r--macros/latex/contrib/dvisirule/dvisirule.dtx498
1 files changed, 498 insertions, 0 deletions
diff --git a/macros/latex/contrib/dvisirule/dvisirule.dtx b/macros/latex/contrib/dvisirule/dvisirule.dtx
new file mode 100644
index 0000000000..f65444d471
--- /dev/null
+++ b/macros/latex/contrib/dvisirule/dvisirule.dtx
@@ -0,0 +1,498 @@
+% \iffalse
+% Copyright 2012-2022 Jiro Senju
+%
+% This package 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
+% any later version.
+%
+% This package 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 package. If not, see <http://www.gnu.org/licenses/>.
+%
+%<package>\NeedsTeXFormat{LaTeX2e}
+%<package>\ProvidesPackage{dvisirule}%
+%<package>[2022/07/07 v0.1 dvisirule]
+%
+%<*driver>
+\documentclass[draft]{ltxdoc}
+%
+\input{fonts}
+\usepackage[dvipdfmx,final]{graphicx}
+\usepackage[final]{listings}
+\lstset{basicstyle=\small\ttfamily,
+ language=TeX,
+ columns=[c]flexible,
+ tabsize=4,
+ %frame=tb,
+ keepspaces=true,
+ %lineskip=-.1ex,
+ belowskip=\medskipamount}
+\usepackage{multicol}
+\usepackage{needspace}
+\usepackage{setspace}
+%
+% hyperref should come last
+\usepackage[dvipdfmx,final,pdfusetitle]{hyperref}
+% CJKbookmarks=true
+% bookmarksdepth=section
+% pdffitwindow=true
+% pdfpagetransition=Dissolve
+% pdfstartview=FitB
+\hypersetup{
+ hyperfootnotes=false,
+ colorlinks=true,
+ linkcolor=blue,
+ % anchorcolor=black,
+ % citecolor=black,
+ % urlcolor=black,
+ bookmarks=true,
+ bookmarksnumbered=true,
+ setpagesize=false,
+ %pdftitle={},
+ %pdfauthor={},
+ pdfpagelayout=SinglePage,
+ pdfpagemode=UseOutlines,
+ pdfstartview=FitH
+}
+%
+\usepackage{\jobname}
+%
+\makeatletter
+% \def\meta@font@select{\slshape}
+% \def\fps@table{htbp}
+\def\fps@figure{htbp}
+%
+\newcommand{\NoDescription}{\vspace*{-.9\baselineskip}}
+%
+% \EnableCrossrefs
+\DisableCrossrefs
+\CodelineIndex
+% \RecordChanges
+%
+\begin{document}
+\MakeShortVerb{\|}
+\DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%\GetFileInfo{\jobname.sty}
+%
+% \title{{\spaceskip=1ex\textsf{\jobname} package \fileversion\\
+% (\texttt{sitabular} environment)}}
+% \author{\texttt{jiro1010senju at gmail dot com}}
+% \date{\filedate}
+% \maketitle
+%
+% Superimpose the hidden\slash covered |\hline| and |\vline| in a LaTeX
+% tabular\slash colortbl environment.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Motivation}
+%
+% Over a decade ago, I need to write down some latex tables in color.
+% Not so many colors used, just two background colors.
+% One is white as a usual background, and the other is gray which is
+% to be easier to distinguish the preceding and succeeding rows from each
+% other.
+% In other words, the tables have two different row colors one after the
+% other.
+%
+% Fortunately we have |\rowcolors| from |xcolor.sty| and it is really
+% helpful, except one thing.
+% The problem is the lines (|\hline|, |\cline| and others) are not shown
+% in the PDF viewer.
+% Technically speaking, if we zoom in\slash out, then the lines appear,
+% but not always.
+% If I change the thickness of the lines, I can always see them.
+% But it is too ugly.
+% It seems highly depending on the monitor resolution and the PDF viewer's
+% internal calculation of the coordinates.
+% Even if I set the width of the lines to 4pt, it can be only one pixel on
+% the screen.
+% It is totally up to the environment of the viewer.
+%
+% To address this issue, I guessed the cause is the order of drawing
+% lines and painting the row background color.
+% E.g. drawing lines first, and then painting the background color next.
+% In that case, the background color may hide the lines due to the
+% internal rounding-up\slash down the calculated coordinates.
+%
+% Some TeXnicians may be able to modify the tabular\slash colortbl
+% environment, and postpone drawing the lines after completing the
+% background color.
+% But I don't have such TeXnique.
+% I had considered a few ways to get what I want,
+% and my solution is to draw the lines again at the end of the page by a
+% new dviware.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Basic approach}
+%
+% \begin{enumerate}
+% \item
+% In |.tex| (actually |.sty|), embed the markers to represent the
+% begin\slash end of a line.
+%
+% \item
+% A new dviware searches the embedded markers, if found, remembers the
+% coordinates in the DVI page of them, and the offset in the DVI file.
+%
+% \item
+% When the dviware reaches the end of the page, it copies the DVI
+% instructions from the marker to the end of the page.
+% I mean appending the line instructions to the page.
+% And replace the the markers by NOP at the original position, to keep
+% silent other dviwares.
+% \end{enumerate}
+%
+% Now the lines are re-drawn over the row background color, and we can
+% always see them clearly.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Compile \& Install}
+%
+% \begin{lstlisting}[gobble=2,xleftmargin=1em]
+% $ cd $this_dir/src
+% $ configure -q
+% $ cd ..
+% $ make -s Dir=/tmp
+% \end{lstlisting}
+%
+% Then you will get these files.
+%
+% \begin{lstlisting}[gobble=2,xleftmargin=1em]
+% /tmp/dvisirule
+% /tmp/dvisirule-bin
+% /tmp/dvisirule-expg.mk
+% /tmp/dvisirule-marker.awk
+% /tmp/dvisirule-pgnum.awk
+% /tmp/dvisirule.sty
+% \end{lstlisting}
+%
+% Now you can install them by
+%
+% \begin{lstlisting}[gobble=2,xleftmargin=1em]
+% $ make InstallBase=/tmp/texmf-dist
+% \end{lstlisting}
+%
+% Here |${InstallBase}| is a make-variable which is referred by other make-variables.
+%
+% \begin{lstlisting}[gobble=2,xleftmargin=1em]
+% InstallBin ?= ${InstallBase}/bin
+% InstallLib ?= ${InstallBase}/lib
+% InstallSty ?= ${InstallBase}/lib/texinputs
+% \end{lstlisting}
+%
+% and the files will be installed to these dirs.
+%
+% \begin{lstlisting}[gobble=2,xleftmargin=1em]
+% ${InstallBin}/dvisirule
+%
+% ${InstallLib}/dvisirule-bin
+% ${InstallLib}/dvisirule-expg.mk
+% ${InstallLib}/dvisirule-marker.awk
+% ${InstallLib}/dvisirule-pgnum.awk
+%
+% ${InstallSty}/dvisirule.sty
+% \end{lstlisting}
+%
+% Please note that these installed dirs have to be recognized by
+% |Kpathsea| since the main |sh| script |dvisirule| searches these
+% sub-files by |kpsewhich(1)|.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Usage}
+%
+% |dvisirule.sty| is provided, and |sitabular| environment is a wrapper
+% of |tabular| (including |colortbl|. You should include |xcolor.sty|
+% or something BEFORE this pkg).
+% The tabular syntax are kept, so you can use it by simply replacing |tabular| by
+% |sitabular|.
+% But it is not a main part of this package.
+% |sitabular| does only embedding the markers and stores the
+% page number to an external file.
+% The main part of this packages is |dvisirule| (shell script) and the
+% internal command |dvisirule-bin| (C\: program).
+% So the usage here is not only including |dvisirule.sty| and
+% |\begin{sitabular}|, but also run |dvisirule| after LaTeX compilation.
+%
+% \begin{lstlisting}[gobble=2,xleftmargin=1em]
+% (a.tex)
+% \usepackage{dvisirule}
+%
+% \begin{sitabular} ... \end{sitabular}
+%
+% latex a.tex
+% cp -p a.dvi a.dvi.save
+% dvisirule a.dvi a-si.dvi
+% mv a-si.dvi a.dvi
+% \end{lstlisting}
+%
+% You don't want run |dvisirule| command unconditionally?\,
+% Good.\,
+% |dvisirule.sty| creates and writes a file the page numbers which
+% contain the line to
+% be superimposed, so when the size of that file is zero, you can
+% skip |dvisirule| command.
+%
+% \begin{lstlisting}[gobble=2,xleftmargin=1em]
+% latex a.tex
+% if [ -s a.sirule ]
+% then
+% cp -p a.dvi a.dvi.save
+% dvisirule a.dvi a-si.dvi
+% mv a-si.dvi a.dvi
+% fi
+% \end{lstlisting}
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \clearpage
+% \section{Demo}
+%
+% \lstinputlisting{/tmp/demoprint}
+%
+% \includegraphics{/tmp/demo.pdf}
+% \bigskip
+%
+% Tested on TeX Live 2019.
+% \clearpage
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Limitation}
+%
+% |\hline|\, supports |\hline\hline| sequence, which means if followed by
+% another |\hline|, it inserts |\vskip\doublerulesep|.
+% This feature doesn't work in |sitabular|. It results a single thick
+% |\hline|. Use |\hhline| (from |hhline.sty|) instead.
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{\texttt{dvisirule} script and sub-programs}
+%
+% The main script runs |dvitype| and other
+% commands internally. You may want to replace some commands by other
+% language specific variants. For |dvitype| command, you can set a
+% environment variable, |$DVITYPE|. If it is set, the main script uses
+% |$DVITYPE| instead of |dvitype|. Here is an example.
+%
+% \begin{lstlisting}[gobble=2,xleftmargin=1em]
+% DVITYPE=pdvitype
+% export DVITYPE
+% dvisirule a.dvi
+% \end{lstlisting}
+%
+% There are two other commands in the same group, |dviselect|
+% (|$DVISELECT|) and |dviconcat| (|$DVICONCAT|).
+%
+% Also the main script refers to |$TMPDIR| environment variable. It
+% specifies a directory where the extracted DVI page(s) are stored temporarily.
+% If it is not set, |/tmp| is used.
+%
+% \subsection{\texttt{dvisirule} --- main shell script}
+%
+% Syntax\,:
+% \lstinputlisting[xleftmargin=2em]{/tmp/help.txt}
+%
+% \begin{enumerate}
+% \item
+% Accepts |.dvi|, and searches |.sirule|.
+% If |.sirule| doesn't exist, exits with an error.
+% If it exists but the size is zero, then exits with a success.
+% \item
+% By an AWK script, |dvisirule-pgnum.awk|, splits |.dvi| per page,
+% dividing those who contains |sitabular| and who doesn't.
+% Sequential pages who doesn't contain |sitabular| are grouped into a
+% single file.
+% \item
+% (for each extracted page which contains |sitabular|)
+% \par
+% By an AWK script, |dvisirule-marker.awk| finds and extracts the
+% markers from the page and the DVI line instructions from it.
+% \item
+% (for each extracted page which contains |sitabular|)
+% \par
+% By a binary program |dvisirule-bin|, copies the line instructions
+% surrounded by the markers to the end of the page, and replaces the
+% markers and the line instructions at the original position (in the
+% DVI page) by NOP instruction, to stop other dviwares complain about
+% the marker.
+% \item
+% Concatenate all pages, and make the final |.dvi|.
+% \end{enumerate}
+%
+% \subsection{\texttt{dvisirule-bin} --- sub binary}
+%
+% This command has two inputs, one is a DVI file and the other is the
+% output from |dvisirule-marker.awk|.
+% The AWK script parses an output of |dvitype| for a single DVI page, and
+% extract and prints SETRULE\slash PUTRULE instructions surrounded by the
+% markers along with the color, the coordinates, and the offset in the DVI
+% file.
+%
+% |dvisirule-bin| command parses the output of the AWK script, and copies
+% those SETRULE\slash PUTRULE instructions to the end of the page. The
+% markers and the instructions at the original offset are replaced by NOP
+% instruction, so that other dviwares don't complain about that such as
+% ``Unknown special'' or something. At last, |dvisirule-bin| creates and
+% writes a new DVI file.
+%
+% You may be wondering is the AWK script really necessary? Why doesn't
+% |dvisirule-|\allowbreak|bin| parse the DVI file by itself\,?
+% Good point. It's just because I'm lazy. I can understand if a single
+% binary operates all these processing, then the required cost (including
+% CPU time) will be smaller. The performance will not be bad. But it is a
+% run-rime performance. The lazy of me wants the develop-time performance
+% too.
+%
+% Roughly speaking, splitting and parsing for each DVI page, and copying
+% the instructions should be done concurrently. If all were implemented by
+% C including multi-threading, the technical hurdle would be rather high.
+% So I chose scripting for splitting and parsing. It can be run
+% concurrently by |"make -j NCPU"|. Since DVI is a binary format, I had to
+% implement it by C. It is OK, and the single-threaded C program can be
+% run in parallel by |"make -j NCPU"| too.
+% This is my laziness.
+%
+% \StopEventually
+%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% \section{Implementation}
+%
+% \subsection{\texttt{.sirule} file}
+%
+% \DescribeMacro{\si@RulePageW}
+% \DescribeMacro{\si@RulePage}
+% Create a file and store the absolute page numbers which contain
+% |sitabular|.
+% \smallskip
+%
+% \begin{macrocode}
+\RequirePackage{zref-abspage}
+%
+\newwrite\si@RulePageW
+\immediate\openout\si@RulePageW=\jobname.sirule%\relax
+\newcommand{\si@RulePage}{%\immediate
+ \write\si@RulePageW{\theabspage}%
+}
+% \end{macrocode}
+%
+% \subsection{marker}
+%
+% \DescribeMacro{\si@bol}
+% \DescribeMacro{\si@eol}
+% Begin/End markers of a line.
+% \smallskip
+%
+% \begin{macrocode}
+\newcounter{si@rule}
+\newcommand{\si@bol}{%
+ \stepcounter{si@rule}%
+ \special{sirule BOL\space\thesi@rule}%
+ \si@RulePage%
+}
+\newcommand{\si@eol}{%
+ \si@RulePage%
+ \special{sirule EOL\space\thesi@rule}%
+ \addtocounter{si@rule}{-1}%
+}
+% \end{macrocode}
+%
+% \subsection{\texttt{\textbackslash hline} and \texttt{\textbackslash vline}}
+%
+% \DescribeMacro{\si@hline}
+% \DescribeMacro{\si@vline}
+% Originally |\hline| issues |\futurelet| internally to support
+% |\hline\hline| sequence. But |\si@hline| issues |\si@eol| just after
+% the original |\hline|. So |\hline\hline| would not work
+% expectedly. Use |\hhline| (|hhline.sty|) instead.
+% \smallskip
+%
+% \begin{macrocode}
+\let\si@Ohline=\hline
+\newcommand{\si@hline}{%
+ \noalign{\si@bol}%
+ \si@Ohline%
+ \noalign{\si@eol}%
+}
+\let\si@Ovline=\vline
+\newcommand{\si@vline}{%
+ \si@bol%
+ \si@Ovline%
+ \si@eol%
+}
+% \end{macrocode}
+%
+% \subsection{\texttt{\textbackslash hhline} if loaded}
+%
+% \DescribeMacro{\si@hline}
+% \DescribeMacro{\si@vline}
+% \NoDescription
+% \smallskip
+%
+% \begin{macrocode}
+\newif\ifsi@hhline
+\@ifundefined{hhline}{}{%
+ \global\si@hhlinetrue%
+ \global\let\si@Ohhline=\hhline%
+ \newcommand{\si@hhline}[1]{%
+ \noalign{\si@bol}%
+ \si@Ohhline{#1}%
+ \noalign{\si@eol}%
+ }%
+}
+% \end{macrocode}
+%
+% \subsection{\texttt{sitabular} environment}
+%
+% \DescribeEnv{sitabular}
+% \smallskip
+%
+% \begin{macrocode}
+\@ifundefined{newcolumntype}{%
+ \global\let\newcolumntype=\@gobbletwo%
+}{}
+\let\si@Otabular=\tabular
+\let\endsi@Otabular=\endtabular
+\newenvironment{sitabular}[1]{%
+ \def\hline{\si@hline}%
+ \ifsi@hhline\def\hhline{\si@hhline}\fi%
+ \newcolumntype{|}{!{\si@vline}}%
+ \begin{si@Otabular}{#1}%
+}{%
+ \end{si@Otabular}%
+}
+% \end{macrocode}
+%
+% \subsection{\texttt{silongtable} environment if loaded}
+%
+% \DescribeEnv{silongtable}
+% \smallskip
+%
+% \begin{macrocode}
+\@ifclassloaded{longtable}{}{%
+ \global\let\si@OLT@hline=\LT@hline%
+ \newcommand{\si@LT@hline}{%
+ \noalign{\si@bol}%
+ \si@OLT@hline%
+ \noalign{\si@eol}%
+ }%
+ \let\si@Olongtable=\longtable%
+ \let\endsi@Olongtable=\endlongtable%
+ \newenvironment{silongtable}[1]{%
+ \def\LT@hline{\si@LT@hline}%
+ \def\si@Ohline{\hline}%
+ \def\hline{\si@hline}%
+ \ifsi@hhline\def\hhline{\si@hhline}\fi%
+ \newcolumntype{|}{!{\si@vline}}%
+ \begin{si@Olongtable}{#1}%
+ }{%
+ \end{si@Olongtable}%
+ }%
+}
+% \end{macrocode}
+%\Finale