%:strip
% Part of the ptx2pdf macro package for formatting USFM text
% copyright (c) 2007-2020 by SIL International
% written by David Gardner and pior editors of ptx-char-style
%
% Permission is hereby granted, free of charge, to any person obtaining  
% a copy of this software and associated documentation files (the  
% "Software"), to deal in the Software without restriction, including  
% without limitation the rights to use, copy, modify, merge, publish,  
% distribute, sublicense, and/or sell copies of the Software, and to  
% permit persons to whom the Software is furnished to do so, subject to  
% the following conditions:
%
% The above copyright notice and this permission notice shall be  
% included in all copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  
% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  
% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND  
% NONINFRINGEMENT. IN NO EVENT SHALL SIL INTERNATIONAL BE LIABLE FOR  
% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  
% CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION  
% WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
%
% Except as contained in this notice, the name of SIL International  
% shall not be used in advertising or otherwise to promote the sale,  
% use or other dealings in this Software without prior written  
% authorization from SIL International.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Milestone macros
\def\NotTriggerPoint#1{\x@\let\csname n@tTrig@#1\endcsname\@ne} %Not all milestones with attributes represent trigger locations.
\def\notlocation#1{\x@\let\csname n@tLocn@#1\endcsname\@ne} %Not all trigger-generating milestones represent unique locations-> keep the trigger around.
\def\IsTriggerPoint#1{\x@\let\csname n@tTrig@#1\endcsname\undefined} 
\let\attr@b\relax
\NotTriggerPoint{xts} %Strongs numbers like 'ms:xts=5447' not trigger points by default.
\NotTriggerPoint{zcustombotmark}
\NotTriggerPoint{zcustomtopmark}
\NotTriggerPoint{zcustomfirstmark}
\NotTriggerPoint{ztocline}

\newif\ifsuppresstr@gger
\def\ch@ckislocation#1{\keeptriggerfalse\suppresstr@ggerfalse\ifcsname n@tLocn@#1\endcsname\keeptriggertrue\fi\ifcsname n@tTrig@#1\endcsname\suppresstr@ggertrue\fi}

\def\mst@nestyle#1{\trace{m}{mst@nestyle:#1 (\milestoneOp)}%
 \xdef\thismil@stone{\detokenize{#1}}% record the name of the style
 \catcode32=12 % make <space> an "other" character, so it won't be skipped by \futurelet
 \catcode13=12 % ditto for <return>
 %\tracingassigns=1
 %\use@ttrSlash
 \futurelet\n@xt\domst@nestyle % look at following character and call \domst@nestyle
}

\let\p@pe=| % for matching
\catcode`\~=12 \lccode`\~=32 % we'll use \lowercase{~} when we need a category-12 space
\catcode`\_=12 \lccode`\_=13 % and \lowercase{_} for category-12 <return>
\lowercase{%
 \def\domst@nestyle{% here, \n@xt has been \let to the next character after the marker
  \mst@nestyletrue
  \initmil@stone%
  \deactiv@tecustomch@rs
  \catcode32=10 % reset <space> to act like a space again
  \catcode13=10 % and <return> is also a space (we don't want blank line -> \par)
  \ifx\n@xt\h@phen\let\n@xt@\startmst@nestyle@minus\else
    \ifx\n@xt~\let\n@xt@\startmst@nestyle@spc\else
      \ifx\n@xt_\let\n@xt@\startmst@nestyle@nl\else
       \ifx\n@xt\p@pe\let\n@xt@\startmst@nestyle@pipe\else
	\let\n@xt@\startmst@nestyle\fi\fi\fi\fi
  %\tracingassigns=0
  \trace{m}{Start style}%
  \n@xt@
 }
 \def\startmst@nestyle@spc~{\startmst@nestyle}%                                             
 \def\startmst@nestyle@nl_{\startmst@nestyle}%
}

\def\startmst@nestyle@pipe|{\trace{m}{Immediate start of attributes}\in@ttribtrue\startmst@nestyle\@ttrSlash}%
\def\startmst@nestyle@minus-#1{%
  \def\milestoneOp{#1}%
  \startmst@nestyle
}

\def\initmil@stone{%called by startmst@nestyle@minus and startch@rstyle@minus.
  \trace{m}{initmil@stone \milestoneOp}%
  \ifmst@nestyle\else %Was this marker defined as a milestone or as a character style
    \edef\thismil@stone{\newch@rstyle}%
  \fi
  \edef\thismil@stoneKey{}\edef\thismil@stoneVal{}% Set by Attributes
  %\xdef\milestoneOp{#1}%
  \edef\attrid{\milestoneOp id}% id / sid / eid, depending.
}

\def\@ttrSlash{\in@ttribtrue
  \trace{m}{Starting attribute collection}%
  \catcode`\/=12 \relax % FIXME Other active chars too?
  \catcode`\|=12
  \@ttrSl@sh}
% using #1#2 eats initial spaces. This means  #1#2 nicely ignores annoying initial spaces, but it also crashes on a spaces-only arg, so check for that.
\def\@ttrSl@sh #1\*{\edef\tmp{\zap@space #1 \empty}\ifx\tmp\empty\else\x@\@@ttrSlash #1\relax\relax\fi}
\def\@@ttrSlash #1#2\relax{\xdef\attrib@rgs{#1#2}\trace{m}{@ttrSlash: Attr:\attrib@rgs}\*}

\def\*{%This might end a + style (c)  or a normal style character style(C), or a milestone style
  \trace{m}{slash *}%
  \ifmst@nestyle
    \proc@ttribs
    \get@ttribute{\thisdefault@ttrkey}%
    \ifx\attr@b\relax\else
      \let\thismil@stoneKey\thisdefault@ttrkey
      \let\thismil@stoneVal\attr@b
    \fi
  %  \ifmst@nestyle\else
  %    \ifx \ss@ChrP\stylet@pe
  %      \endch@rstylepls*
  %    \else
  %      \endch@rstyle*
  %    \fi
  %  \fi
    \mst@nestylefalse
    \processmil@stone
  \else{*}%
  \fi}% USFM3 'self closing marker' milestone

\let\milestoneOp\empty
\let\thismil@stone\empty
\let\thisattrmil@stone\empty
\newif\ifmst@nestyle \mst@nestylefalse

\def\processmil@stone{\trace{m}{Milestone \thismil@stone (\milestoneOp), \csname thisch@rstyle\endcsname}%
  \ifx\milestoneOp\empty
    \st@ndalonemilestone
  \else 
    \if\milestoneOp s\relax\st@rtmilestone\else
      \if\milestoneOp e\relax\@ndmilestone\else
      \st@ndalonemilestone\fi 
    \fi
  \fi
   %\xdef\thisch@rstyle{\mcpeek}%
   \def\d@##1+##2+##3\E{\d@code{##1}{##2}\edef\thisch@rstyle{\tmp}}\mctop
   \trace{m}{\if e\milestoneOp After-\fi Milestone style is \thisch@rstyle, stystack is: \styst@k }%
   \global\let\milestoneOp\empty
   \s@tfont{\thisch@rstyle}{\styst@k}% set up font attributes
}

\def\startmst@nestyle{%What actually changes between the beginning of a milestone and the end-marker? Attribute values!
   \trace{m}{startmst@nestyle}%
   \op@ninghooks{before}{\thismil@stone}{\styst@k}%
   \csname init@ttribs\endcsname
}

\def\dr@pmilest@ne#1+#2+#3\E{% This itterates the stack to kills the TOP matching milestone 
  \edef\MSt@mp{#1}%
  \ifx\MSt@mp\empty
    \let\d@=\cstackrelax %Stop processing (permanent change)
  \else
    \ifx\ss@Mstn\MSt@mp\relax %It's a milestone
      \x@\pars@msid #2;;;\E
      \ifx\MStyp@\MSch@cking\relax
        \ifx\mstone@id\MSch@ckid
          %\csname endit@#1\endcsname
          \trace{m}{Found \MStyp@ (\MSch@ckid)}%
          \let\d@=\empty %just a signal to skip this one.
          \tempfalse % clear error flag if set
        \else
          \trace{m}{Found \MStyp@, but ids do not match "\MSch@ckid"!="\mstone@id"}%
          \temptrue% flag error
        \fi
      \fi
    \fi
    \ifx\d@\empty
      %Two possible actions here: clear all matching milestones or only the top one.
      %standard is vague about nesting/cancellation. Current implementation 
      %keeps going down if there's no sid/eid to match. 
      %\ifx\MSch@ckid\empty
        \let\d@=\dr@pmilest@neB % Keep tracking down, to build \@ut, but no more testing.
      %\else
        %\let\d@=\cstackrelax %Top match only.  permanent change
      %\fi
    \else
      \ifx\@ut\empty \xdef\@ut{#1+#2}\else
	\xdef\@ut{\@ut,#1+#2}%
      \fi
    \fi
  \fi
  \trace{m}{dr@pmilest@ne: \@ut}%
}

\def\dr@pmilest@neB#1+#2+#3\E{% This itterates the stack to kills the TOP matching milestone 
  \edef\MSt@mp{#1}%
  \ifx\MSt@mp\empty
    \let\d@=\cstackrelax %Stop processing 
  \else
    \ifx\@ut\empty \xdef\@ut{#1+#2}\else
      \xdef\@ut{\@ut,#1+#2}%
    \fi
  \fi
  \trace{m}{dr@pmilest@neB: \@ut}%
}

\def\dr@pmilestone#1#2{%Kill a milestone that might be burried in the stack, and might be nested.
  \trace{m}{Dropping milestone #1 from \mcstack}% 
  \edef\MSch@cking{#1}%
  \edef\MSch@ckid{#2}%
  \tempfalse
  \let\@ut=\empty
  \let\d@=\dr@pmilest@ne
  \mcdown
  \xdef\mcstack{\mcstack@mpty}%
  \ifx\@ut\empty
    \s@tstyst@k
  \else
    \rebuild@mcstack{\@ut,}%
    %\xdef\mcstack{\@ut,\mcstack@mpty}%
  \fi
  \trace{m}{Stack now: \mcstack, stystack:\styst@k}%
  \iftemp
    \message{End-milestone of class '\MSch@cking', id '\MSch@ckid' partially matched one or 
      more open milestones, but no match on the id was found, sid and eid must match exactly}%
  \fi
}
%+csty_milestone
% Operations on the current milestone(s)
\def\zapres@rved#1{%
    \edef\smst@mp{\zap@space #1 \empty}%
    \edef\smst@mp{\expandafter\zap@comma \smst@mp,\empty}%
    \edef\smst@mp{\expandafter\zap@plus \smst@mp+\empty}%
} 

% If there is '\s \qt-s\*' in the input, should the qt-s have effect on the paragraph style? If the boolean is true, 
% then it does not, and the paragaph starts differently to '\qt-s\* \s'. Note that this does not trigger any extra paragraph break,
% all it does is ensure that a parargaph waiting to start *is* safely started.
\newif\ifDefineParBeforeMilestone
\DefineParBeforeMilestonetrue 

\def\st@rtmilestone{%
  % There may multiple milestones of a given type (can't sensibly have both \qt-s |Jesus\* and 
  % \qt-s |Pilate\* active at the same time (except quote in quote), but in some cases it might make sense to do something similar.)
  \deactiv@tecustomch@rs
  \get@ttribute{\attrid}\ifx\attr@b\relax %if sid is set, sid/eid must match, and may contain letters,numbers,underscore.
    \x@\zapres@rved\x@{\thismil@stoneVal}%
    \xdef\thisattrmil@stone{\thismil@stone;\smst@mp}%
    \def\smst@mp{without ID}%
  \else
    \x@\zapres@rved\x@{\thismil@stoneVal;\attr@b}%
    \xdef\thisattrmil@stone{\thismil@stone;\smst@mp}%
    \def\smst@mp{with \attrid =\attr@b\space}%
  \fi
  \ifDefineParBeforeMilestone\leavevmode\fi
  \mcpush{\ss@Mstn}{\thisattrmil@stone}%
  \trace{m}{Milestone \smst@mp\space stacked, \mcstack}%
  \let\tmp\thisattrmil@stone
  \csname d@code-m\endcsname
  \global\let\thisattrmil@stone\tmp
  \upd@teMsPrefix
  \let\styst@k=\empty
  \s@tstyst@k%
  \@ttrMilestonefalse
  \ifx\thismil@stoneVal\empty\else
    \@ttrMilestonetrue
  \fi
  \kill@PossParamCache
  \trace{m}{Style stack now: \mcstack}%
  \op@ninghooks{start}{\thismil@stone}{\styst@k}%
}

\def\@ndmilestone{%
  \trace{m}{@ndmilestone.  stack now: \mcstack}%
  \let\h@@kstyst@k\styst@k
  \cl@singhooks{end}{\thismil@stone}{\h@@kstyst@k}%
  \get@ttribute{\attrid}%attrid is id/sid/eid (set in init@ttribs)
  \ifx\attr@b\relax 
  \dr@pmilestone{\thismil@stone}{}%
  \else
  \dr@pmilestone{\thismil@stone}{\attr@b}%
  \fi
  \trace{m}{Style stack now: \mcstack}%
  \upd@teMsPrefix
  \cl@singhooks{after}{\thismil@stone}{\h@@kstyst@k}\the\afterh@@ks
  \global\let\attr@b\empty\global\let\attrid\empty
  \global\let\thismil@stone\empty
  \global\let\thisattrmil@stone\empty
}

\def\figmil@stone{zfiga}

% Stand alone milestones are mainly triggers for other code, figure insertion or similar things.
% trigger-ms:\thismil@stone and trigger-ms:\thismil@stone=attrib  are user-supplied triggers, and are expected to be USFM. They self-destruct
% ms:\thismil@stone=attrib is defined by e.g. defzvar and is expected to be simple text. They may self-destruct
% MS:\thismilestone is TeX code to generate zgaps, zrules etc. They never self-destruct.

\def\st@ndalonemilestone{% 
  \trace{m}{st@ndalonemilestone}%
  \ifx\attrid\empty
    \let\attr@b\relax
  \else 
    \get@ttribute{\attrid}%
  \fi
  \edef\tmp{\thismil@stone}%
  %\relax\trace{m}{st@ndalonemilestone(\meaning\tmp, \meaning\zv@@r) \attrid=\attr@b}%
  \ifx\tmp\zv@@r       
    \trace{m}{Leaving vmode for zvar}%  Special case... things get confused if the par is started by the milestone.
    \leavevmode
  \fi
  \mcpush{\ss@Mstn}{\thismil@stone}%
  \trace{m}{Milestone stacked, \mcstack}%
  \t@stpublishability{\thismil@stone}%
  \getp@ram{type}{\thismil@stone}{\thismil@stone}%
  \ifx\p@ram\relax\let\p@ram\empty\fi
  \trace{m}{\thismil@stone \space type=\p@ram}%
  \ifx\p@ram\empty\else
    \leavevmode
    \trace{m}{Leaving vmode for \thismil@stone \space type \p@ram}%
  \fi
  \ifn@npublishable\else
    \op@ninghooks{start}{\thismil@stone}{\styst@k}%
  \fi
  \let\oldc@rref\c@rref\let\olddc@rref\dc@rref
  %\tracingmacros=1
  %\tracingassigns=1
  \ifx\attr@b\undefined\let\attr@b\relax\fi
  \ifx\attr@b\relax
    \keeptriggerfalse
  \else
    \edef\@@tmp{ms:\thismil@stone=\x@\detokenize\x@{\attr@b}}%
    \trace{m}{Checking for  \@@tmp}%
    \keeptriggertrue %By default keep ms: type triggers if they have an attribute .
    \ifcsname \@@tmp\endcsname
      \trace{mx}{Running \@@tmp (\x@\meaning\csname\@@tmp\endcsname)}%
      \bgroup
       \csname \@@tmp\endcsname 
      \egroup
      \ifkeeptrigger\else 
        \trace{m}{Destroying \@@tmp}%
        \x@\global\x@\let\csname \@@tmp\endcsname\undefined
      \fi
    \else
      \trace{m}{No \@@tmp defined}%
  \fi\fi
  %\tracingassigns=0
  %\tracingmacros=0
  % execute any standard code for this milestone.
  \ifcsname MS:\thismil@stone\endcsname \csname MS:\thismil@stone\endcsname\fi 
  \ifx\attr@b\relax
    \ch@ckislocation{\thismil@stone}% 
    \ifsuppresstr@gger
      \trace{m}{No trigger for \thismil@stone}%
    \else
      \runtrigg@rs{ms:\thismil@stone}%
    \fi
  \else
    \ch@ckislocation{\thismil@stone}% Non-locations can be multiple use, so their value is kept. Sets keeptrigger true if this is not a location. 
    \ifsuppresstr@gger
      \trace{m}{No trigger for \thismil@stone}%
    \else
      \runtrigg@rs{\mkp@cref{\id@@@}{\x@\detokenize\x@{\attr@b}}}%
      \ifdiglot
	\runtrigg@rs{\mkp@cref{\id@@@\c@rrdstat}{\x@\detokenize\x@{\attr@b}}}%
      \fi
      \runtrigg@rs{ms:\thismil@stone=\x@\detokenize\x@{\attr@b}}%
    \fi
  \fi
  \ifkeeptrigger% Not a location, leave c@rref what it used to be
    \trace{m}{Restoring c@rref to \oldc@rref}%
    \global\let\c@rref\oldc@rref\global\let\dc@rref\olddc@rref
  \else% This milestone is a named location 
    \ifsuppresstr@gger\else
      \ifx\attr@b\relax
        \trace{m}{This milestone has no location (\thismil@stone \id@@@\attr@b)}%
      \else
        \trace{m}{This is a unique location (\id@@@\attr@b)}%
        \xdef\c@rref{\id@@@\attr@b}%
        \ifx\v@rse\empty\global\p@rnum=\ifhmode 1\else 0\fi
         \ch@ckadjustments
        \fi
      \fi
    \fi
  \fi
  \let\h@@kstyst@k\styst@k
  \ifn@npublishable
    \n@npublishablefalse %restore to publishable
  \else
    \cl@singhooks{end}{\thismil@stone}{\h@@kstyst@k}%\
  \fi
  \dr@pmilestone{\thismil@stone}{}%
  \cl@singhooks{after}{\thismil@stone}{\h@@kstyst@k}\the\afterh@@ks\relax
  \let\thismil@stone\empty
}%

\def\upd@teMsPrefix{%Build a prefix based on all currently-in-force milestones.
  \trace{m}{upd@teMsPrefix}%
  \xdef\mspr@fix{}\let\d@=\mil@st@necheck\mcup
  \ifx\mspr@fix\empty\else\xdef\mspr@fix{ms:\mspr@fix|}\trace{m}{msPrefix set to \mspr@fix}\fi
}
\xdef\equ@l{=}
\def\pars@msid#1;#2;#3;#4\E{\edef\MStyp@{#1}\edef\k@yv@al{#2}\def\mstone@id{#3}}

\x@\def\csname d@code-m\endcsname{%Modify contents of \tmp to only include bits of the stack value of use for styles.
  \x@\pars@msid \tmp;;;\E
  \edef\tmp{\ifx\k@yv@al\empty\else\k@yv@al|\fi\MStyp@}%
}
\def\mil@st@necheck#1+#2+#3\E{%The milestone has a key value and possibly an ID field. Ignore the id for building the prefix
  \edef\MSt@mp{#1}%
  \ifx\MSt@mp\ss@Mstn
    \x@\pars@msid #2;;;\E
    \trace{m}{parsed #2->\k@yv@al, \mstone@id}%
  \xdef\mspr@fix{\ifx\mspr@fix\empty\else \mspr@fix+\fi\ifx\k@yv@al\equ@l\else\k@yv@al|\fi\MStyp@}\fi}
 
\newtoks\tmpt@ks
\def\exp@ndmspr@fix#1{%for each potential prefix, call #1 with \@lso defined
   \tmpt@ks{#1}%
   \trace{m}{Expanding \mspr@fix}%
   \def\D@IT##1{\edef\@lso{ms:##1|}\trace{m}{adding option \@lso to styles}\the\tmpt@ks}%
   \it@mcount=0
   \x@\@xp@ndmspr@fix \mspr@fix\E
   %\ifnum \it@mcount>1
     %\let\@lso\mspr@fix \the\tmpt@ks
   %\fi
}

%simple + separated list processing
\def\l@stitem #1\E{}
\newcount\it@mcount
\newcount\afterwordpages \afterwordpages=0 % How many pages are to be expected after those inserted by \zfillsignature, e.g. maps and diagrams
\def\e@chitem#1+#2\E{%
  \edef\it@mtmp{#1}\ifx\it@mtmp\empty\let\nxt@item\l@stitem\else
    \advance\it@mcount by 1
    \D@IT{#1}\fi
  \x@\nxt@item #2+\E
}

\def\@xp@ndmspr@fix ms:#1|{%
   \trace{m}{list: #1}%
   \let\nxt@item\e@chitem
   \x@\nxt@item #1+\E
}
%-csty_milestone
\def\attrid{}
\notlocation{zvar}
%\notlocation{zuseperiph}
\def\m@kenumberns#1{\m@kedigitsother\x@\m@kenumb@rE #1\END} % real numbers are terminated by a training space. But if we have mixed text, a space may not be wanted.
\def\m@kenumber#1{\m@kedigitsother\x@\m@kenumb@r #1 =}% The version with a space to stop premature expansion.
\def\m@kenumb@r#1={\p@sheof\edef\@@result{\scantokens{#1\noexpand}}\p@peof\m@kedigitsletters}
\def\m@kenumb@rE#1\END{\p@sheof\edef\@@result{\scantokens{#1\noexpand}}\p@peof\m@kedigitsletters}
\def\defzvar#1#2{\x@\def\csname ms:zvar=#1\endcsname{#2}}
\x@\def\csname MS:zrule\endcsname{%
  \endgraf
  \bgroup
    \get@ttribute{cat}%
    \ifx\attr@b\relax\else\x@\s@tc@tprefix\x@{\attr@b}\fi
    \get@ttribute{width}%A
    \ifx\attr@b\relax
      \s@tsideskips{zrule}{-1pt}%
      \edef\rule@wid{\the\dimexpr \hsize - \leftskip - \rightskip\relax}%
    \else
      \m@kenumber{\attr@b}%
      \edef\rule@wid{\the\dimexpr \@@result\hsize\relax}%
    \fi
    \get@ttribute{colour}%A
    \ifx\attr@b\relax
      \get@ttribute{color}%A
      \ifx\attr@b\relax
        \getp@ram{bordercolour}{zrule}{\styst@k}\let\attr@b\p@ram
      \fi
    \fi
    \ifx\attr@b\relax\else
      \m@kenumber{\attr@b}%
      \x@\checkh@x\@@result\end \let\b@drcol\rgb@out
      \trace{m}{zrule colour  \b@drcol}%
    \fi
    \get@ttribute{thick}%
    \ifx\attr@b\relax
      \getp@ram{borderwidth}{zrule}{\styst@k}%
      \ifx\p@ram\relax
        \def\rule@thk{0.5pt}%
        \def\@thinlinedesc{Default zrule thickness of \rule@thk}%
      \else
        \edef\rule@thk{\the\dimexpr \p@ram\FontSizeUnit\relax}%
        \def\@thinlinedesc{Style sheet 'BorderWidth \p@ram'}%
        %\def\rule@thk{0.5pt}%
      \fi
    \else
      \m@kenumber{\attr@b}%
      \def\@thinlinedesc{zrule attribute}%
      \let\rule@thk\@@result%
    \fi
    \get@ttribute{raise}%A
    \ifx\attr@b\relax
      \getp@ram{raise}{zrule}{\styst@k}%
      \ifx\p@ram\relax
	\edef\rule@adjust{0pt}%
      \else
	\edef\rule@adjust{\p@ram\FontSizeUnit}%
      \fi
    \else
      \m@kenumber{\attr@b}%
      \edef\rule@adjust{\the\dimexpr \@@result\relax}%
    \fi
    \get@ttribute{style}%A
    \ifx\attr@b\relax
      \getp@ram{borderstyle}{zrule}{\styst@k}%
    \else     
      \let\p@ram\attr@b
    \fi
    \ifx\p@ram\relax
      \def\rule@style{plain}%
    \else
      \ifcsname drawzrule-\p@ram\endcsname
        \let\rule@style\p@ram
      \else
        \def\rule@style{plain}%
        \message{unrecognised rule style '\attr@b' near \c@rref}%
      \fi
    \fi
    \get@ttribute{align}%
    \ifx\attr@b\relax
      \def\rule@pos{c}%
    \else
      \let\rule@pos\attr@b
    \fi
    \trace{m}{Rule \rule@wid, thick \rule@thk,  style \rule@style}%
    \csname drawzrule-\rule@style\endcsname
  \egroup 
  \lastdepth=\prevdepth
}

\x@\def\csname drawzrule-plain\endcsname{% 
  \bc@lsetup
  \let\thinlin@type\tlt@R
  \thinlinecheck{\rule@thk}{}{zrule}{\@thinlinedesc}%
  \hbox{\raise \rule@adjust\hbox to \hsize{\hskip\leftskip\ifx\rule@pos\@lignLeft\else\hfil\fi
    \bc@l\vrule height \rule@thk depth 0pt width \rule@wid \endbc@l
    \ifx\rule@pos\@lignRight\else\hfil\fi\hskip\rightskip}}%
}

\def\getcustommarknum#1{%
  \ifcsname m@rknum#1\endcsname\trace{ma}{Already got #1}\else\addnewm@rk{#1}\fi
  \getm@rknum{#1}%
  \let\custommarknum\m@rknum
}
\def\getcustomm@rknum{%
  \get@ttribute{type}% 
  \ifx\attr@b\relax
    \getcustommarknum{user}%
  \else
    \getcustommarknum{\attr@b}%
  \fi
}

\x@\def\csname MS:zcustommark\endcsname{%
  \ifnum\currentgrouptype>0
    \savingmarks
  \fi
  \trace{ma}{zcustommark}%
  \getcustomm@rknum
  \get@ttribute{value}%
  \trace{m}{zcustommark(\m@rknum) \attr@b}%
  \ifx\attr@b\relax\else
    \x@\x@\x@\marks\x@\m@rknum\x@{\attr@b}%
  \fi
}

\x@\def\csname MS:zsetref\endcsname{%
  %\trace{M}{This is zsetref "\attribsus@d"}%
  \tempfalse % Did an actual reference get set properly, or was this called with an unattributed string reference 
  \def\tmp{bkid}\ifx\attribsus@d\tmp\tempfalse%  Is this called normally, or just with the default arg?
  \else
    \temptrue
    \get@ttribute{book}\ifx\attr@b\relax\else
      \x@\ifx\csname book\g@tdstat\endcsname\attr@b\else
        \x@\global\x@\let\csname book\g@tdstat\endcsname\attr@b
        {\resetallcolsfalse\ifbookresetcallers\let\\=\carefulResetAutonum\the\n@tecl@sses\fi}%
      \fi
    \fi
    \get@ttribute{chapter}\ifx\attr@b\relax\else
      \global\let\ch@pter\attr@b
    \fi
    \get@ttribute{verse}\ifx\attr@b\relax\else
      \global\let\v@rse\attr@b
    \fi
  \fi 
  \get@ttribute{bkid}\ifx\attr@b\relax\else
    \ifx\id@@@\attr@b\else
      \iftemp % standard calling notation used
        \global\let\id@@@\attr@b
        \trace{M}{Book ID will now be \attr@b}%
        {\resetallcolsfalse\ifbookresetcallers\let\\=\carefulResetAutonum\the\n@tecl@sses\fi}%
      \else % try to parse as "Book Ch:V"
        \trace{M}{Unexpected format for a book ID (\attr@b). Trying to parse it like a reference}%
        \@p@rseref{\attr@b}%
        \ifx\p@rsedV\relax
          \global\let\id@@@\attr@b
          \trace{M}{Book ID will now be \attr@b}%
          {\resetallcolsfalse\ifbookresetcallers\let\\=\carefulResetAutonum\the\n@tecl@sses\fi}%
        \else
          \global\let\ch@pter\p@rsedC
          \global\let\v@rse\p@rsedV
          \ifx\id@@@\p@rsedID\else
            \global\let\id@@@\p@rsedID
            {\resetallcolsfalse\ifbookresetcallers\let\\=\carefulResetAutonum\the\n@tecl@sses\fi}%
          \fi
        \fi
      \fi
  \fi
  \let\attr@b\relax
}

\x@\def\csname MS:vid\endcsname{%
  \get@ttribute{h}\ifx\attr@b\relax\else
    \x@\ifx\csname book\g@tdstat\endcsname\attr@b\else
      \x@\global\x@\let\csname book\g@tdstat\endcsname\attr@b
      {\resetallcolsfalse\ifbookresetcallers\let\\=\carefulResetAutonum\the\n@tecl@sses\fi}%
    \fi
  \fi
  \get@ttribute{ref}\ifx\attr@b\relax\else
    \x@\@p@rseref\x@{\attr@b}%
    \ifx\p@rsedV\relax
      \message{Could not parse reference '\attr@b'}%
    \else
      \global\let\ch@pter\p@rsedC
      \global\let\v@rse\p@rsedV
      \ifx\id@@@\p@rsedID\else
        \global\let\id@@@\p@rsedID
        {\resetallcolsfalse\ifbookresetcallers\let\\=\carefulResetAutonum\the\n@tecl@sses\fi}%
      \fi
    \fi
  \fi
  \let\attr@b\relax
}

\x@\def\csname MS:zcustombotmark\endcsname{%
\getcustomm@rknum
\botmarks\m@rknum
}
\x@\def\csname MS:zcustomfirstmark\endcsname{%
\getcustomm@rknum
\firstmarks\m@rknum
}
\x@\def\csname MS:zcustomtopmark\endcsname{%
\getcustomm@rknum
\topmarks\m@rknum
}

\NotTriggerPoint{zgap}
\x@\def\csname MS:zgap\endcsname{%
  \endlastp@rstyle{zgap}%
  \endgraf
  \get@ttribute{dimension}%A
  \ifx\attr@b\relax
    \let\gap@dim\baselineskip%
  \else
    \trace{m}{zgap: \meaning\attr@b}%
    \m@kenumber{\attr@b}%
    \trace{m}{zgap: \meaning\attr@b}%
    \let\gap@dim\@@result%
  \fi
  \trace{m}{zgap \gap@dim}%
  \vbox{}\penalty10000\vskip\gap@dim\relax%
}

\NotTriggerPoint{zfillsignature}
\x@\def\csname MS:zfillsignature\endcsname{{%
  \get@ttribute{pagenums}%
  \ifx\attr@b\relax\else
    \ifcsname \attr@b pagenums\endcsname \csname attr@b pagenums\endcsname
    \else
      \message{valid options for pagenums attribute of zfillsignature are 'do' and 'no'}%
    \fi
  \fi
  \ifdim\pagetotal>0pt
    \endgraf\endpage
  \fi
  \get@ttribute{pages}%
  \ifx\attr@b\relax
    \message{pages attribute of zfillsignature must be supplied at the moment}%
  \else
    \trace{m}{zfillsignature pg \the\pageno, printed: \the\totalp@ges}%
    \x@\m@kenumber\x@{\attr@b}%
    \count255=\@@result
    \get@ttribute{extra}% How many extra pages
    \ifx\attr@b\relax\def\tmppages{0}\else
      \x@\m@kenumber\x@{\attr@b}%
      \let\tmppages=\@@result
    \fi
    \count254=\numexpr \afterwordpages + \tmppages + \totalp@ges \relax
    \xdef\totalp@gecheck{\the\totalp@ges}%
    \count253=\count254 \divide\count253 by \count255
    \edef\tmpa{\the\count253}% NOTE that dimexpr a/b **ROUNDS**, where \divide truncates. 
    \trace{m}{\tmpa= \the\count254/\the\count255}%
    \count253=\numexpr \count255 - (\count254 - \tmpa*\count255 ) \relax
    \ifnum\count253=\count255 
      \count253=0
    \fi
    \trace{m}{\the\count254 pages accounted for, \the\count253 (= \the\count255 -(\the\count254 - \tmpa * \the\count255)) needed to complete the signature of \the\count255}%
    \get@ttribute{periph}%
    \ifx\attr@b\relax\else
      \x@\def\x@\TPILB{\x@\zgetperiph\x@|\attr@b\*}%
    \fi
    \loop
      \ifnum\count253>0
      \zEmptyPage
      \advance\count253 by -1
    \repeat
  \fi
}}
\def\runmilestone#1#2{% Macro for when a stand-alone milestone is wanted from a hook/TeX or other code
  \def\attrib@rgs{#2}\def\thismil@stone{#1}\parse@ttribs{#2}%
  \get@ttribute{\thisdefault@ttrkey}%
  \st@ndalonemilestone}

\x@\def\csname start-zgetperiph\endcsname{\let\periph@@@\attr@b}
\x@\def\csname end-zgetperiph\endcsname{\let\periph@@@\empty}

\x@\def\csname MS:zifvarset\endcsname{% Attributes var, emptyok
  % set ztruetext or zfalsetext to produce output, depending on result.
  % testing is of zvar variable var, if the variable is non-empty, the result is true.
  % If it's set but empty, then if emptyok is given but not "F", then the
  % varible having been defined *at all* is sufficent to be considered true.
  %
  %\message{MSzifvarset}%
  \get@ttribute{var}%
  \tempfalse
  \ifx\attr@b\relax
    \trace{m}{zifvarset: no attribute supplied!}%
  \else
    \ifcsname ms:zvar=\attr@b\endcsname
      \x@\let\x@\tmp\csname ms:zvar=\attr@b\endcsname
      \ifx\tmp\empty
        \get@ttribute{emptyok}%
        \x@\uppercase\x@{\x@\edef\x@\attr@b\x@{\attr@b}}% Allow lower case as well.
        \ifx\attr@b\relax\else
          %\message{\meaning\attr@b\meaning\false}%
          \ifx\attr@b\false
          \else
            \temptrue % Empty but defined variable
          \fi
        \fi
      \else
        \ifx\tmp\relax\else\temptrue\fi % non-empty
      \fi
    \fi
  \fi
  \s@ttruefalsetext
}

\x@\def\csname MS:zifhook\endcsname{%
  %Check to see if there are start/end hooks for the specified marker
  %and run the appropriate text / command
  \get@ttribute{marker}%
  \tempfalse
  \ifx\attr@b\relax
    \trace{m}{zifhook: no attribute supplied!}%
  \else
    \ifcsname begin-\attr@b\endcsname\temptrue\fi
    \ifcsname start-\attr@b\endcsname\temptrue\fi
    \ifcsname end-\attr@b\endcsname\temptrue\fi
    \ifcsname after-\attr@b\endcsname\temptrue\fi
    \trace{m}{zifhook: [\attr@b] = \iftemp true\else false\fi}%
  \fi
  %\tracingassigns=1
  \s@ttruefalsetext
  %\tracingassigns=0
}

\def\s@ttruefalsetext{%
  \iftemp
    \gdef\ztruetext##1\ztruetext*{\r@gurgitatedtrue\p@sheof\scantokens{##1}\p@peof\r@gurgitatedfalse}%
    \gdef\zfalsetext##1\zfalsetext*{}%
  \else
    \gdef\ztruetext##1\ztruetext*{}%
    \gdef\zfalsetext##1\zfalsetext*{\r@gurgitatedtrue\scantokens{##1}\r@gurgitatedfalse}%
  \fi
}

%ISBN and barcode routines
%
% First, barcode generating code from 
%http://tex.stackexchange.com/questions/6895/is-there-a-good-latex-package-for-generating-barcodes
%
\def\b@rheight{10ex}

\def\barcode#1#2#3#4#5#6#7{\begingroup% EAN13 barcode - used to encode ISBN10 (with a prefix and new checksum) and ISBN13 (directly)
  \message{barcode #1 #2 #3 #4 #5 #6}%
  \dimen0=0.1em
  \def\stack##1##2{\oalign{##1\cr\hidewidth##2\hidewidth}}%
  \def\0##1{\kern##1\dimen0}%
  \def\1##1{\vrule height\b@rheight width##1\dimen0}%
  \def\L##1{\ifcase##1\bc3211##1\or\bc2221##1\or\bc2122##1\or\bc1411##1%
    \or\bc1132##1\or\bc1231##1\or\bc1114##1\or\bc1312##1\or\bc1213##1%
    \or\bc3112##1\fi}%
  \def\R##1{\bgroup\let\next\1\let\1\0\let\0\next\L##1\egroup}%
  \def\G##1{\bgroup\let\bc\bcg\L##1\egroup}% reverse
  \def\bc##1##2##3##4##5{\stack{\0##1\1##2\0##3\1##4}##5}%
  \def\bcg##1##2##3##4##5{\stack{\0##4\1##3\0##2\1##1}##5}%
  \def\bcR##1##2##3##4##5##6{\R##1\R##2\R##3\R##4\R##5\R##6\11\01\11\09%
    \endgroup}%
  \stack{\09}#1\11\01\11\L#2%
  \ifcase#1\L#3\L#4\L#5\L#6\L#7\or\L#3\G#4\L#5\G#6\G#7%
    \or\L#3\G#4\G#5\L#6\G#7\or\L#3\G#4\G#5\G#6\L#7%
    \or\G#3\L#4\L#5\G#6\G#7\or\G#3\G#4\L#5\L#6\G#7%
    \or\G#3\G#4\G#5\L#6\L#7\or\G#3\L#4\G#5\L#6\G#7%
    \or\G#3\L#4\G#5\G#6\L#7\or\G#3\G#4\L#5\G#6\L#7%
  \fi\01\11\01\11\01\bcR}

\def\barcodeV#1#2#3#4#5#6{\begingroup% EAN5
    \dimen0=0.1em
    \dimen1=\b@rheight
    \hskip -0.3em %Proper alignment
    \edef\b@rheight{\the \dimexpr 0.7\dimen1\relax}%
    \message{barcodeV (\b@rheight) #1 #2 #3 #4 #5 (#6)}%
    \edef\@price{#6}%
    \def\stack##1##2{\hbox{\vbox{\hbox{##2}\hbox{##1}}}}%
    \def\0##1{\kern##1\dimen0}%
    \def\1##1{\vrule depth 0pt height \b@rheight width##1\dimen0}%
    \def\L##1{\ifcase##1\bc3211##1\or\bc2221##1\or\bc2122##1\or\bc1411##1%
      \or\bc1132##1\or\bc1231##1\or\bc1114##1\or\bc1312##1\or\bc1213##1%
      \or\bc3112##1\fi}%
    \def\G##1{\bgroup\let\bc\bcg\L##1\egroup}% reverse
    \def\S{\01\11}%
    \def\bc##1##2##3##4##5{\stack{\0##1\1##2\0##3\1##4}##5}%
    \def\bcg##1##2##3##4##5{\stack{\0##4\1##3\0##2\1##1}##5}%
    \count255=\numexpr 3*#1 + 9*#2 + 3*#3 + 9*#4 + 3*#5\relax
    \count254=\count255 
    \loop\ifnum\count255 >9 \advance\count255 by -10 \repeat
    \trace{m}{Calculated check digit for EAN-5: \the\count254->\the\count255}% 
    \setbox1=\hbox{\vbox{\lineskip=0pt \baselineskip=0pt \relax\hbox{\stack{\01\11\01\12}{}\ifcase\count255 
          \G#1\S\G#2\S\L#3\S\L#4\S\L#5 \or \G#1\S\L#2\S\G#3\S\L#4\S\L#5
      \or \G#1\S\L#2\S\L#3\S\G#4\S\L#5 \or \G#1\S\L#2\S\L#3\S\L#4\S\G#5
      \or \L#1\S\G#2\S\G#3\S\L#4\S\L#5 \or \L#1\S\L#2\S\G#3\S\G#4\S\L#5
      \or \L#1\S\L#2\S\L#3\S\G#4\S\G#5 \or \L#1\S\G#2\S\L#3\S\G#4\S\L#5
      \or \L#1\S\G#2\S\L#3\S\L#4\S\G#5 \or \L#1\S\L#2\S\G#3\S\L#4\S\G#5
    \fi}\ifx\@price\empty\else\setbox0\hbox to 5em{\hss\@price\hss}\dimen0=\dimexpr \ht0 + \dp0 \relax\box0\kern-\dimen0 %
       \fi}}%
    %\showbox1
    \box1
  \endgroup
}

\newcount\num@rgs
\def\@count@rgs#1#2{\let\n@xt\relax\ifx#1\relax\else\advance \num@rgs by 1\relax \ifx#2\relax \else\let\n@xt\@count@rgs \fi\fi \n@xt #2}
\def\count@rgs#1{\num@rgs=0  \@count@rgs#1 \relax\relax\trace{m}{#1 has \the\num@rgs\space digits}}

%\barcode 9789731650937
%
\def\r@encodeten#1#2#3\relax{%Recode a 10 digit ISBN as a 13 digit barcode. The check digit is different beyween ISBN10 and ISBN13
  \ifx#2\relax
    \edef\r@code{\r@code\the\numexpr 10-\count255\relax}%
    \trace{m}{Updated check digit. Barcode should be: \r@code}% 
    \x@\barcode\r@code
    \let\n@xt\relax
  \else
    \advance\count255 by \numexpr #1 + 3*#2\relax
    \loop\ifnum\count255 >9 \advance\count255 by -10 \repeat
    \edef\r@code{\r@code#1#2}%
    \let\n@xt\r@encodeten
  \fi
  \n@xt#3\relax
}

%ISBNs use minuses to separate number groups. There seems no guaranteed pattern
%  Call barcode using stripped down version
\def\bcode#1-{\count@rgs{#1}%
  \lineskip=10pt \lineskiplimit=0pt
  \ifnum\num@rgs=13 \barcode#1\relax
    \else
    \ifnum\num@rgs=10 \count255=0 %\tracingmacros=1\tracingassigns=1 
      \let\r@code\empty\r@encodeten 978#1\relax\relax
     \else
      \MSG{*** ISBN Barcodes can have 10 or 13 digits (\the\num@rgs\space were supplied)}%
     \fi
  \fi\ifversion{2}{}{\ifnum \num@rgs=10 \else \space\fi}}%
% strip off minuses one by one. There's probably a more efficient way, but this seems to work
% Call with \isbn _code_-\emptything-
\def\emptything{}
\def\isbn#1-#2-{\def\bc{#1#2}\def\pb{#2}\trace{m}{Building barcode: \bc (\pb)}\ifx\pb\emptything\let\next=\bcode\else\let\next=\isbn\fi\expandafter\next\bc-}
%
%\def\pr@ce#1.#2.{\def\bc{#1#2}\def\pb{#2}\trace{m}{Building price barcode: \bc (\pb)}\ifx\pb\emptything\let\next=\bcode\else\let\next=\pr@ce\fi\expandafter\next\bc.}

%A beautiful ISBN has "ISBN 123-435-763-124" above the top exactly matching the
%width of the barcode. Do some maths to get it right.  Adding up numbers above,
%the barcode seems like it should be 12*.7+.4+.5+.4=9.7em wide. It actually
%seems to come out to 9.5.  To account for kerning after the glyph width I set the text to a width 9.55
\newdimen\ISBNfontdim
\ISBNfontdim=10pt
\newif\ifnoScaleAboveISBNtext\noScaleAboveISBNtextfalse

\def\ISBNfont{Source Code Pro}
\def\ISBN#1{\leavevmode
  \font\belowISBN="\ISBNfont" at \ISBNfontdim % Outside group so that it's accessible for prices
  \bgroup
  %\trace{m}
  \trace{m}{ISBN barcode for \attr@b, using \ISBNfont at \the\ISBNfontdim}%
  \belowISBN\setbox0\hbox{ISBN #1}\dimen0=478em\divide\dimen0 \wd0 \multiply\dimen0\ISBNfontdim%scale calculation by 50.
  %I don't assme the above will work exactly, so measure with a space and typeset with a some glue.
  \edef\tmp{\the\dimexpr 0.02\dimen0\relax}%
  \ifnoScaleAboveISBNtext
    \edef\tmp{\ISBNfontdim}%
  \else
    \trace{m}{dimen0 is \the\dimen0, font will be at \tmp}%
  \fi
  \font\aboveISBN="\ISBNfont"  at \tmp \relax
  %\trace{m}{dimen0 is \the\dimen0. AboveISBNfont is \tmp}%
  \vbox{\lineskip=0.2ex \lineskiplimit=0pt \everypar={}%
   %\message{here we go....}%
   \hbox{\hbox to 0.9em{\hss}% All measurements *outside* the top-boxe use main belowISBN font, the top-box uses scaled font.
       \hbox to 9.55em{\aboveISBN \hskip 0pt minus 0.5ex ISBN\hskip 0.3em plus 1fil minus 0.25em #1\hskip 0pt minus 0.5ex}}%
   %\message{Drawing ISBN}%
   \hbox{\expandafter\isbn#1--}
  }%
  \egroup
  %\message{ISBN done}%
}


%\zISBNbarcode accepts 2 options: height="normal/medium/short" and isbn
\x@\def\csname MS:zISBNbarcode\endcsname{%
  \bgroup
\def\b@rheight{10ex}
  \get@ttribute{height}\ifx\attr@b\bc@short\def\b@rheight{5ex}\else\ifx\attr@b\bc@medium\def\b@rheight{7ex}\fi\fi
  \get@ttribute{font}\ifx\attr@b\relax\else
    \let\ISBNfont\attr@b
  \fi
  \get@ttribute{fontheight}\ifx\attr@b\relax\else
    \m@kenumber{\attr@b}%
    \ISBNfontdim=\@@result\relax
  \fi
  \get@ttribute{isbn}%
  \ifx\attr@b\relax
    \get@ttribute{var}\ifx\attr@b\relax\else
      \ifcsname ms:zvar=\attr@b\endcsname
        \x@\let\x@\tmp\csname ms:zvar=\attr@b\endcsname
        \let\attr@b\tmp
      \fi
    \fi
  \fi
  \m@kenumberns{\attr@b}%
  \hbox{\ISBN{\@@result}%
    \get@ttribute{price}%
    \ifx\attr@b\relax
      \edef\@price{}%
      \get@ttribute{pricevar}\ifx\attr@b\else
        \ifcsname ms:zvar=\attr@b\endcsname
          \x@\let\x@\tmp\csname ms:zvar=\attr@b\endcsname
          \let\@price\tmp
        \fi
      \fi
    \else
      \edef\@price{\attr@b}%
    \fi
    \get@ttribute{pricecode}%
    \ifx\attr@b\relax
      \get@ttribute{pricecodevar}\ifx\attr@b\else
        \ifcsname ms:zvar=\attr@b\endcsname
          \x@\let\x@\tmp\csname ms:zvar=\attr@b\endcsname
          \let\attr@b\tmp
        \fi
      \fi
    \fi
    \ifx\attr@b\relax\else
      \m@kenumberns{\attr@b}%
      \belowISBN\x@\barcodeV \@@result{\@price}\relax\relax\relax\relax%
    \fi
  }\egroup}

\def\proc@strong#1{%
  \get@ttribute{align}%
  \ifx\attr@b\relax \let\al@gn\@lignLeft\else\let\al@gn\attr@b\fi
  \get@ttribute{strongs}%
  \trace{m}{Got strongs \attr@b}%
  \ifx\attr@b\relax \else\edef\tmpz{#1}%
    \x@\dostr@ngs\x@{\x@\tmpz\x@}\x@{\x@\al@gn\x@}\attr@b+++\E
  \fi
}
\def\dostr@ngs#1#2#3#4#5#6#7\E{%
% #1 style, #2 align, #3 #4 #5 #6 4 digits, #7 dummy
 \ifn@npublishable\else
  \trace{m}{dostr@ngs #1, #2, #3, #4, #5, #6, #7}%
  \bgroup\s@tfont{#1}{#1}%
    \setbox0=\hbox{\if #4+\relax #3\else\if #6+\relax #3\else #3#4\fi\fi}%
    \setbox1=\hbox{\if #4+\relax\else\if #5+\relax #4\else\if #6+\relax #4#5\else #5#6\fi\fi\fi}%
    \dimen0=\ifdim\wd0>\wd1 \wd0\else\wd1\fi
    \getp@r@m{raise}{#1}\ifx\p@ram\relax\else\dimen1=\p@ram\trace{m}{raising by \the\dimen1, from \p@ram}\raise\dimen1\fi
    \vbox{\s@tbaseline{#1}{#1}\trace{m}{dostr@ngs #1 baselineskip=\the\baselineskip}%
                          \hbox to \dimen0{\if#2r\relax\hfil\fi\unhbox0\if#2l\relax\hfil\fi}%
                          \hbox to \dimen0{\if#2r\relax\hfil\fi\unhbox1\if#2l\relax\hfil\fi}%
    }\egroup
 \fi
}
