%   VERTICAL RULERS 2.3 Oct 1996 for Latex 2.09 or 2e, plain TeX, amsTeX
%            by  Zhuhan JIANG, University of New England, Australia NSW 2351.
%                Email: zhuhan@neumann.une.edu.au
%
%   PURPOSE: Make a vertical ruler, numbering consecutively so that
%            any part of an article can be pinpointed immediately.
%            Move vruler freely up and down, left and right.
%         
%            There are no packages to my knowledge that number lines
%            one by one without missing certain lines, particularly
%            when there are many maths equations in the text. So vruler
%            is a good alternative for people writing text of versatile
%            format or lots of maths formulas.
%   COMMANDS:
%     \setvruler[<SCALE>][<INITIAL_COUNT>][<STEP>][<DIGITS>][<MODE>]%
%              [<ODD_HSHIFT]>][<EVEN_HSHIFT>][<VSHIFT>][<HEIGHT>]
%         <general LaTeX material-01>
%     \unsetvruler  % optional
%         <general LaTeX material-02>
%
%         <SCALE>   distance between two consecutive vruler markings
%         <INITIAL_COUNT> first marking reading
%         <STEP>    is the line count increment
%         <DIGITS>  number of digits required for ruler markings
%         <MODE> =0 if each page has same vruler marking, =1 if otherwise
%         <ODD_HSHIFT>  horizontal shift for odd pages
%                       from the default value for the vruler
%         <EVEN_HSHIFT> horizontal shift for even pages
%                       from the default value for the vruler
%         <VSHIFT>  vertical shift from default value for vruler
%         <HEIGHT>  height of vertical ruler
%
%     \vrulercount   - next mark reading on the vertical ruler
%
%     \setdefault{cmdname}{n}{default_1}{..}{default_n} (re)set macro
%         \cmdname[#1][..][#n] to take default_1 to default_n respectively,
%         so that \cmdname[][xy] is same as \cmdname[default_1][xy][default..].
%         You don't need to use \setdefault unless you would like to change
%         the default setting for macros in vruler.sty or elsewhere.
%
%   DEFAULTS:
%     The parameters of \setvruler admit defaults.
%     Hence e.g. \setvruler alone is same as
%         \setvruler[10pt][1][1][4][1][0pt][0pt][0pt][\textheight]
%     and e.g. \setvruler[][20] is same as \setvruler[10pt][20]
%
%   NOTES:
%     1.  If you are using multicol.sty, then you might want to move
%         the vruler into the center to separate the columns.
%
%     2.  If you use \topskip other than the default value, then
%         you will have to alter <VSHIFT> and <HEIGHT> parameters
%         in \setvruler accordingly (which is simple). 
%
%     3.  It is best to choose baselineskip as <SCALE> so that line
%         synchronisation is often optimal. Use e.g. 5+ to denote
%         the line immediately after marking number 5 if necessary.
%
%     4.  In twosided book style in LaTeX2e, the initial numbering
%         of title page  via  \begin{titlepage} is actually onepage
%         away. To overcome this, either do not include title page in
%         the vruler environment, or set initial number #2
%         to a number (a page ahead) so that the resulting
%         initial number is what one needs.
%           
%     5.  Version 1.0 of VRULER.STY for LaTeX is released in
%         July 1993.
%
%   EXAMPLE:   see end of this file.
%         You may run the example by simply removing the line 
%         containing \endinput
%         
%BEGINMACROS
%
\ifx\VrulerDefined\undefined\let\next\relax\else
\message{NOT reloaded}\let\next\endinput\fi\next
\xdef\VrulerDefined{}% avoid TeX output routine manipulated twice.
%
\message{2.3 <24/10/96>}%
%
{\catcode`\@=11\relax \def\temp@macro{\space\space\space\space}%
\wlog{\temp@macro VRULER version 2.3 Octorber 1996 By Z Jiang}%
\wlog{\temp@macro University of New England, Australia}%
\wlog{\temp@macro Email: zhuhan@neumann.une.edu.au}}%
\xdef\EntryVruler{\the\catcode`\@}\catcode`\@=11\relax %  SAVE @'s STATUS
\let\temp@@@macro=\wlog\def\wlog#1{}%
%
\newdimen\temp@dim \newdimen\b@xheight\newdimen\lineh@ight 
\newbox\outputb@x\newbox\bufferbox\newbox\tempb@x
\newcount\refn@\newcount\tot@l\newcount\rulercount
\let\@outputpage@backup\@outputpage \let\plainoutput@backup\plainoutput
%
% NUMBER with left flushed zeros  \fillzeros[<WIDTH>]<NUMBER>
\newcount\temp@@ \newcount\temp@
\def\fillzeros[#1]#2{\temp@@=#2\relax\ifnum\temp@@<0\temp@@=-\temp@@\fi
\temp@=1 %
\loop\ifnum\temp@@<10 \else \divide\temp@@ by 10 \advance\temp@ by 1 \fi
   \ifnum\temp@@=10\relax\temp@@=11\relax\fi \ifnum\temp@@>10 \repeat
\ifnum#2<0\advance\temp@1\relax-\fi
\loop\ifnum\temp@<#1\relax0\advance\temp@1\relax\fi \ifnum\temp@<#1 \repeat
\temp@@=#2\relax\ifnum\temp@@<0\temp@@=-\temp@@\fi \relax\the\temp@@}%
%
%  PLAIN TEX adjustment
\ifx\textheight\undefined 
  \newdimen \textheight \newdimen \textwidth \textheight=\vsize \textwidth=\hsize
  \font\tiny=cmr5 \let\c@page\pageno \def\oddsidemargin{0pt}%
  \let\evensidemargin\oddsidemargin \def\headsep{2\topskip}%
\fi
%
% \makevruler[<SCALE>][<INITIAL_COUNT>][<STEP>][<DIGITS>][<HEIGHT>]
\def\makevruler[#1][#2][#3][#4][#5]{\begingroup\offinterlineskip
\textheight=#5\vbadness=10000\vfuzz=120ex\overfullrule=0pt%
\global\setbox\bufferbox=\vbox to \textheight{\tiny%
{\parskip=0pt\hfuzz=150em\b@xheight=\textheight
\lineh@ight=#1\global\rulercount=#2%
\tot@l\b@xheight\divide\tot@l\lineh@ight\advance\tot@l2%
\refn@1\vskip-\lineh@ight\vskip1pc%
\loop\setbox\tempb@x=\hbox to0cm{{\hfil\textcolor{black}{\fillzeros[#4]\rulercount}}}%
\ht\tempb@x\lineh@ight\dp\tempb@x0pt\box\tempb@x\break
\advance\refn@1\global\advance\rulercount#3\relax
\ifnum\refn@<\tot@l\repeat}}\endgroup}%
%
% MAKE VRULER into \box\outputb@x
\def\SET[#1][#2][#3][#4][#5][#6][#7][#8][#9]{%
\ifRuler@Started\else\global\rulercount=#2\fi \global\Ruler@Startedtrue
\begingroup\hbadness=10000\hfuzz=150em
\ifnum#5=0\makevruler[#1][#2][#3][#4][#9]\else
\makevruler[#1][\rulercount][#3][#4][#9]\fi\endgroup 
\begingroup\vfuzz=120ex\vbadness=10000%
\global\setbox\outputb@x=\vbox{\b@xheight=\ht\bufferbox
\hbox{\hskip-50pt % default initial adjustment 
   \advance\b@xheight#8\lower\b@xheight%
   \hbox{\ifodd\c@page\hskip#6\else\hskip#7\fi \copy\bufferbox}\nobreak
   \hskip50pt \nobreak \ifodd\c@page \hskip-#6 \else\hskip-#7 \fi \nobreak
   \lower\ht\tempb@x\hbox{\box\tempb@x}}}\endgroup }%
%
\newtoks\toksone\newtoks\tokstwo\newtoks\toksthree
\newtoks\toksfour\newtoks\toksfive \newif\ifRuler@Started \Ruler@Startedfalse
\def\set@vruler[#1][#2][#3][#4][#5][#6][#7][#8][#9]{%
\ifx\pageno\undefined % this is considered as LaTeX
    % we assume all LaTeX versions have \@outputpage in the form of
    % \@outputpage= ...\vbox{ ... \vbox{...}...}... , where 2nd \vbox
    % contains the true content. 
  \toksfive=\expandafter{\@outputpage\s@ftymark}%temp toks
  \long\def\parse@macro ##1\vbox##2##3\s@ftymark{%
  \def\part@@one{##1}\def\part@@two{##2}\def\part@@three{##3}}%
  \expandafter\parse@macro\the\toksfive
  \let\part@one\part@@one \let\part@five\part@@three
  \toksfive=\expandafter{\part@@two\s@ftymark}%
  \expandafter\parse@macro\the\toksfive
  \let\part@two\part@@one \let\part@three\part@@two \let\part@four\part@@three
  \toksone=\expandafter{\part@one}\tokstwo=\expandafter{\part@two}%
  \toksthree=\expandafter{\part@three}\toksfour=\expandafter{\part@four}%
  \toksfive=\expandafter{\part@five}%
%
\edef\@outputpage{\the\toksone \noexpand\vbox{\the\tokstwo \noexpand\vbox{%
  \noexpand\SET[\noexpand#1][\noexpand#2][\noexpand#3][\noexpand#4][\noexpand#5][\noexpand#6][\noexpand#7][\noexpand#8][\noexpand#9]%
  \noexpand\temp@dim=\noexpand\textheight
  \noexpand\advance\noexpand\temp@dim by \noexpand\headsep
  \noexpand\hbox{% box things together
  \noexpand\rlap{\noexpand\raise\temp@dim\box\outputb@x}%
  \noexpand\setbox\noexpand\tempb@x=\noexpand\vbox{\the\toksthree}%
  \noexpand\box\noexpand\tempb@x}\the\toksfour}}\the\toksfive}%
%
\else % now for plain TeX
\def\plainoutput{\textheight=\vsize \SET[#1][#2][#3][#4][#5][#6][#7][#8][#9]%
  \setbox\tempb@x\vbox{\makeheadline\pagebody\makefootline}%from plain.tex
  \shipout \vbox {\hbox{\hskip 15pt
  \rlap{\temp@dim=\textheight\advance\temp@dim by \headsep
  \raise\temp@dim\box\outputb@x }\hskip-15pt \box\tempb@x }}%
  \advancepageno \ifnum\outputpenalty>-\@MM \else\dosupereject\fi }%
\fi}%
%
\def\unsetvruler{\Ruler@Startedfalse \let\@outputpage\@outputpage@backup
                 \let\plainoutput\plainoutput@backup}%
%
\ifx\new@measures\undefined\let\setvruler\set@vruler\fi
%
% LEAVE MACROS
\let\wlog\temp@@@macro\let\temp@@@macro\undefined@
\catcode`\@=\EntryVruler\relax
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% if you delete everything below, the macros are still valid, 
% except that you have to specify all the macro parameters for
% \setvruler explicitly and completely
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
\xdef\EntryVruler{\the\catcode`\@}\catcode`\@=11\relax
%
%  NEW MEASURES etc (parameter defaulting mechanism given by macros below)
\def\new@measures{%
  \def\temp@@macro##1##2##3{\expandafter\ifx\csname ##3temp##2##1\endcsname
     \relax\edef\next{\noexpand\csname new##1\noexpand\endcsname
                      \csname ##3temp##2##1\endcsname}%
     \else\let\next\relax\fi\next}%
  \def\temp@macro##1{%
     \temp@@macro{##1}{@}{}\temp@@macro{##1}{@@}{}\temp@@macro{##1}{@@@}{}}%
  \temp@macro{count}\temp@macro{toks}\temp@macro{box}\temp@macro{read}%
  \temp@@macro{if}{@}{if}\temp@@macro{if}{@@}{if}\temp@@macro{if}{@@@}{if}%
  \def\temp@@macro##1{\expandafter\ifx\csname temp##1dim\endcsname
     \relax\edef\next{\noexpand\csname newdimen\noexpand\endcsname
                      \csname temp##1dim\endcsname}%
     \else\let\next\relax\fi\next}%
  \temp@@macro{@}\temp@@macro{@@}\temp@@macro{@@@}%
}%
\let\temp@@@macro=\wlog\def\wlog#1{}\new@measures
%
%%% GENERAL STACK
\def\make@STKcount{\csname newcount\endcsname
  \STKcount\global\STKcount=0\relax}%
\ifx\STKcount\undefined@
  \def\next{\make@STKcount}\else\def\next{}\fi
\next % ensures stack pointer not flushed if this piece of code
      % is loaded again
%
\long\def\push#1{\global\advance\STKcount1\relax
\expandafter\gdef\csname STK\the\STKcount\string~\endcsname{#1}}%
%
\def\popnil{\expandafter\let\expandafter\temp@macro
  \csname STK\the\STKcount\string~\endcsname
  \ifnum\STKcount>0\global\expandafter\let
    \csname STK\the\STKcount\string~\endcsname=\undefined@
    \global\advance\STKcount-1%
  \else
    \def\temp@macro{}\global\STKcount=0%
  \fi\relax % \temp@macro for pop
}%
%
\def\pop{\popnil\temp@macro}%
%
%% GET PARAMETERS
\long\def\get@nepara[#1][#2]{{\def\next@{#2}%
\ifx\next@\empty\push{#1}\else\push{#2}\fi}\ag@in}%
%
\long\def\get@para\left@#1\right@{%
\def\check@{%
 \ifx[\next@ \def\full@####1{\get@nepara[#1]####1}%
 \else \def\full@{\get@nepara[#1][#1]}\fi
 \full@}%
\futurelet\next@\check@}%
%
\long\def\do@nepara\left@#1\right@#2\p@r@end{%
\gdef\p@r@data{#2}\global\advance\p@r@count1\get@para\left@#1\right@}%
%
\def\ag@in{\ifx\p@r@data\empty \def\next@{\relax
\getp@r@s\run@CMD}\else
\def\next@{\expandafter\do@nepara\p@r@data\p@r@end}\fi
\next@}%
%
\def\run@CMD{\csname STK\the\STKcount\string~\endcsname}%
%
\def\num@to@word#1{\ifcase #1 \or
   \def\temp@macro{one}\or   \def\temp@macro{two}\or
   \def\temp@macro{three}\or \def\temp@macro{four}\or
   \def\temp@macro{five}\or  \def\temp@macro{six}\or
   \def\temp@macro{seven}\or  \def\temp@macro{eight}\or
   \def\temp@macro{nine}\else \def\temp@macro{}\fi
\temp@toks=\expandafter{\temp@macro}}%
%
\temp@@count=1 % make nine newtoks, if they don't already exist
\loop \num@to@word{\temp@@count}%
  \expandafter\ifx\csname p@r@\the\temp@toks\endcsname\relax
    \temp@@toks={newtoks}\expandafter\csname\expandafter\the
    \expandafter\temp@@toks\expandafter\endcsname
    \csname p@r@\the\temp@toks\endcsname\fi
  \advance\temp@@count by 1 \ifnum\temp@@count<10 \repeat
% 
\ifx\p@r@count\undefined \newcount\p@r@count\fi
\long\def\st@ckparas#1\p@r@end{%
\global\p@r@count=0\gdef\p@r@data{#1}\ag@in}%
%
% PARAMETER ASSIGNMENT % use \temp@count
\def\getp@r@s{\temp@count=\p@r@count
{\loop
 \ifnum\temp@count>0 %
 \expandafter\let\expandafter
 \temp@macro\csname STK\the\STKcount\string~\endcsname
 \ifcase\temp@count
 \or \global\p@r@one=\expandafter{\temp@macro}%
 \or \global\p@r@two=\expandafter{\temp@macro}%
 \or \global\p@r@three=\expandafter{\temp@macro}%
 \or \global\p@r@four=\expandafter{\temp@macro}%
 \or \global\p@r@five=\expandafter{\temp@macro}%
 \or \global\p@r@six=\expandafter{\temp@macro}%
 \or \global\p@r@seven=\expandafter{\temp@macro}%
 \or \global\p@r@eight=\expandafter{\temp@macro}%
 \or \global\p@r@nine=\expandafter{\temp@macro}%
 \else \errmessage{Parameter capacity exceeded.}%
     % this should never happen:  TeX's max para no. is 9
 \fi
 \global\expandafter\let
 \csname STK\the\STKcount\string~\endcsname=\undefined@%
 \global\advance\STKcount-1%
 \global\advance\temp@count-1\relax
 \fi
 \ifnum\temp@count>0 %
\repeat}}%
%
\def\clrp@r@s{%GLOBALLY clear
\global\p@r@one={}\global\p@r@two={}\global\p@r@three={}%
\global\p@r@four={}\global\p@r@five={}\global\p@r@six={}%
\global\p@r@seven={}\global\p@r@eight={}\global\p@r@nine={}}%
%
\def\read@paras#1{\temp@@@count=1 %use \temp@@@count and \temp@@count
  \loop \num@to@word{\the\temp@@@count}\csname p@r@\the\temp@toks\endcsname={}%
      \advance\temp@@@count by 1 \ifnum\temp@@@count<10 \repeat
  \temp@@@count=1 \temp@@count=#1 %
  \def\read@one@para##1{\num@to@word{\temp@@@count}%
       \def\temp@macro{\left@ ##1\right@}%
       \temp@@@toks=\expandafter{\temp@macro}%
       \csname p@r@\the\temp@toks\endcsname\expandafter{\temp@macro}%
       \advance\temp@@@count by 1 \read@continue}%
  \def\read@continue{\num@to@word{\temp@@@count}% which uses \temp@macro
       \ifnum\temp@@@count>\temp@@count \let\next@@\make@default
          \edef\temp@@macro{\the\p@r@one\the\p@r@two\the\p@r@three\the\p@r@four
          \the\p@r@five\the\p@r@six\the\p@r@seven\the\p@r@eight\the\p@r@nine}%
       \else \let\next@@\read@one@para
       \fi \next@@}\read@continue}%
%
\def\make@@default#1#2{\temp@count=#2\relax \temp@@count=1 %used \temp@@macro
  \loop \num@to@word{\temp@@count}%
      \ifnum\temp@@count>\temp@count \csname p@r@\the\temp@toks\endcsname={}%
      \else \csname p@r@\the\temp@toks\endcsname
            =\expandafter{\expandafter[\expandafter
            \the\csname p@r@\the\temp@toks\endcsname]}\fi
      \advance\temp@@count by 1 %
      \ifnum\temp@@count<10 \repeat
  \edef\temp@macro{\the\p@r@one\the\p@r@two\the\p@r@three\the\p@r@four
       \the\p@r@five\the\p@r@six\the\p@r@seven\the\p@r@eight\the\p@r@nine}%
  \temp@toks=\expandafter{\temp@macro}%
  \temp@@toks=\expandafter{\temp@@macro}%
  \expandafter\let\expandafter\temp@macro\csname #1\endcsname
  \expandafter\ifx\csname #1@ raw\endcsname\relax
      \expandafter\let\csname #1@ raw\endcsname\temp@macro\fi
  \expandafter\edef\csname#1\endcsname{%
      \noexpand\push{\noexpand\edef\noexpand\next@@{%
      \noexpand\noexpand \noexpand \csname \noexpand#1@ raw\noexpand\endcsname
      \the\temp@toks}%
  \noexpand\popnil\noexpand\clrp@r@s\noexpand\next@@}\noexpand\st@ckparas
      \the\temp@@toks \noexpand\p@r@end}}%
%
% \setdefalut{cmdname}{n}{default1}{..}{default_n}
%  then \cmdname[#1][..][#n] can be defaulted.
\def\setdefault#1#2{\def\make@default{\make@@default{#1}{#2}}\read@paras{#2}}
%
% best strategy (e.g) to define \foo[#1][#2]{#3} so as to default #1 and #2
% while making #3 compulsory in brace bracket.
%    1.  define \foo@[#1][#2]#3 as normal (what you wish)
%    2.  define \foo[#1][#2]#{\foo@[#1][#2]} to make {#3} mandatory
%    3.  use \setdefault{foo}{2}{one}{two} to default #1=one and #2 to two
%
% DEFAULT MECHANISM END: this piece of code can be included in any
% package and can be reloaded any times without overruning the resources.
% 
%%%%%%%  make defaults %%%%%%%%%%%
\setdefault{setvruler}{9}{11pt}{1}{1}{4}{1}{0pt}{0pt}{0pt}{\textheight}%
%
\let\wlog\temp@@@macro\let\temp@@@macro\undefined@
\catcode`\@=\EntryVruler\relax
\newcommand{\linenos}{\setvruler[12pt][1][1][1][7][580pt][580pt][-6pt][55pc]
\setvruler[12pt][1][1][1][7][25pt][20pt][-6pt][55pc]}
\endinput
%
%ENDMACROS
% 
% Application example
\documentstyle[vruler,twoside]{article}
       \setlength{\textwidth}{2.5in}
       \setlength{\oddsidemargin}{3cm}
       \setlength{\evensidemargin}{6cm}
       \overfullrule=0pt \parindent=0pt
\begin{document}
\advance\textwidth 3cm %2cm is better for plain TeX
\setvruler [][][][][][\textwidth]
         This is a simple example, in which we have
         placed vertical rulers on the left for
         odd numbered pages and on the right for
         even numbered pages. \newpage

         This is the second page and is thus an even
         numbered page. Please see that the vertical
         ruler is now on the right, and is approximately
         of the same distance from the text margin as
         the vertical ruler on the first page from
         the left margin there. \newpage
\unsetvruler
         The following pages, in fact only this page, will
         not be appended with the vertical rulers.\newpage
\setvruler[][\rulercount]
         This page will be added with the vertical ruler again.
         Here the numbering marking of the vertical ruler picks
         up where it was left. Nevertheless, we may start with
         any new number. \newpage

         This is another page. Please see that both this and
         the previous pages have vruler on the left side.
\end{document}
