%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Module: ZzTeX Horizontal Mode Facilities % % Synopsis: This module provides various facilities that operate in % horizontal mode, within a paragraph. See also ZZHMODEB. % % Author: Paul C. Anagnostopoulos % Created: 21 September 1989 % % Copyright 1989--2020 by Paul C. Anagnostopoulos % under The MIT License (opensource.org/licenses/MIT) % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Starting Paragraphs % -------- ---------- % The following token register is executed at the beginning of % every paragraph. \definetoks{\everyparagraph} \everyparagraph = {} % This is what we have to do at the beginning of every paragraph: \everypar = {\requiredeverypar \the\everyparagraph} % The following command ensures that we are in horizontal mode, % without doing anything if we already are. \def \ensurepar {\unhbox \voidbox} % The following command fakes up the start of a paragraph while % leaving us in vertical mode. \def \fakepar {% \endgraf \vspace{\parskip}% \requiredeverypar} % Paragraph Penalties % --------- --------- \definecount{\zclubsv}{-100000} % Overridden \clubpenalty. \definecount{\zclubct}{1} % Overridden paragraph count. \def \overrideclubpenalty #1{% {penalty} \if \eqlp{\zclubsv}{-100000}\global\zclubsv = \clubpenalty \fi \global\clubpenalty = #1\relax \global\zclubct = \if \vmodep -1\else 0\fi \relax} \declareeverypar{\zclubpar} \def \zclubpar {% \ifnum \zclubct=0 \global\clubpenalty=\zclubsv \global\zclubsv=-100000\relax \fi \global\advance \zclubct 1\relax} % Single-Character Commands % ---------------- -------- % Name Description % \ Control space % \! Negative sixth space; negative thin space in math; % callout in code % \" Dieresis (umlaut) accent % \# Pound sign % \$ Dollar sign % \% Percent sign % \& Ampersand % \' Acute accent % \( (reserved % \) for user) % \* \discretionary{}{}{} % \+ Hair space % \, Sixth space; thin space in math % \- Discretionary hyphen % \. Dot accent % \/ Italic correction % \0 \phantom{0} % \1 -- \9 (reserved for user) % \: List element separator % \; Third space; thick space in math % \< (reserved for user) % \= Macron accent; prefix for tag namespace % \> (reserved for user) % \? (reserved for user) % \@ At-sign % \H Hungarian umlaut accent % \L Polish suppressed L % \O Scandinavian O slash % \P Paragraph sign (pilcrow) % \S Section sign % \[ (reserved for user) % \\ Backslash % \] (reserved for user) % \^ Circumflex accent % \_ Underscore % \` Grave accent % \b Bar-under accent % \c Cedilla accent % \d Dot-under accent % \g Ogonek accent % \h Small horizontal space % \i Dotless i % \j Dotless j % \l Polish suppressed l % \o Scandinavian o slash % \r ring accent % \t Tie-after accent % \u Breve accent % \v Hacek accent % \x \ % \y } (reserved for user, for index command abbreviations) % \z / % \{ Left brace % \| Vertical bar; \Vert in math mode % \} Right brace % \~ Tilde accent % Characters % ---------- % These definitions are in alphabetical order. \def \AA {% %~ Ring A (Angstrom). %^named_char \ensurepar \if \mathmodep \mtext{\AA}% \else \r{A}% \fi} \def \aa {% %~ Ring a. %^named_char \ensurepar \if \mathmodep \mtext{\aa}% \else \r{a}% \fi} \chardef \AE = "1D %~ Scandinavian AE. \chardef \ae = "1A %~ Scandinavian ae. \chardef \ampersand = `\& %~ Ampersand. \let \& = \ampersand \chardef \atsign = `\@ %~ At sign. \let \@ = \atsign \def \backslash {% %~ Backslash. %^named_char \ensurepar \if \mathmodep \zmbackslash \else \if \monoencodingp \char "5C\relax \else \PSbackslash \fi\fi} \let \\=\backslash \def \baselinebullet #1{% {size} %~ Bullet set on baseline. \zrequiredoodad{\zdoodadfont}{#1}% \hbox{\zdoodadfont .}} \def \bullet {% %~ Bullet. %^named_char \ensurepar \if \mathmodep \zmbullet \else \PSbullet \fi} \def \cent {% %~ Cent sign. %^named_char \ensurepar \PScent} \let \cents = \cent \def \copyright {% %~ Copyright symbol. %^named_char \ensurepar \PScopyright} \def \cdquote {''} %~ Close double quote. %^named_char \def \dagger {% %~ Dagger. %^named_char \ensurepar \if \mathmodep \zmdagger \else \PSdagger \fi} \def \ddagger {% %~ Double dagger. %^named_char \ensurepar \if \mathmodep \zmddagger \else \PSddagger \fi} \def \dollar {% %~ Dollar sign. %^named_char \zprehyph{\dollarhyph}% \if \monoencodingp \char "24\relax \else \PSdollar \fi \zposthyph{\dollarhyph}} \let \$ = \dollar \def \ellipsis {% %~ Text ellipsis. \if \mathmodep \ldots \else \unbreakable\thickspace .\unbreakable\thickspace .\unbreakable\thickspace .\thickspace \ignorespaces \fi} \def \emdash {---} %~ Em dash. %^named_char \def \endash {--} %~ En dash. %^named_char \def \greater {% %~ Greater-than sign %^named_char \ensurepar \if \monoencodingp \char "3E\relax \else \PSgreater \fi} \def \>{% %~ Greater-than sign. %^named_char \relax \if \mathmodep \plainerror \else \greater \fi} \chardef \hash = `\# %~ Pound sign, hash, octothorpe. \let \# = \hash \def \hat {% %~ Hat symbol. %^named_char \ensurepar \if \mathmodep \zmhat \else \char "5E\relax \fi} \chardef \i = "10 %~ Dotless i. \chardef \j = "11 %~ Dotless j. \def \L {\PSpolishL} %~ Uppercase Polish L. %^named_char \def \l {\PSpolishl} %~ Lowercase Polish l. %^named_char % \lbrace and \rbrace cannot start with \ensurepar, because that won't % work following a \left or \right command. However, the \relax is required. \def \lbrace {% %~ Left brace. %^named_char \relax \if \mathmodep \zmlbrace \else \if \monoencodingp \char "7B\relax \else \PSbraceleft \fi\fi} \let \{ = \lbrace \def \less {% %~ Less-than sign. %^named_char \ensurepar \if \monoencodingp \char "3C\relax \else \PSless \fi} \let \< = \less \chardef \O = "1F %~ Slashed O. \chardef \o = "1C %~ Slashed o. \chardef \OE = "1E %~ OE diphthong. \chardef \oe = "1B %~ oe diphthong. \def \odquote {``} %~ Open double quote. %^named_char \def \P {% %~ Paragraph symbol (pilcrow). %^named_char \ensurepar \PSparagraph} \chardef \percent = `\% %~ Percent sign. \let \% = \percent \def \perthousand {% %~ Per thousand symbol. %^named_char \ensurepar \PSperthousand} \def \prellipsis {% %~ Text ellipsis with no left space. .\unbreakable\thickspace .\unbreakable\thickspace .\thickspace \ignorespaces} \def \rbrace {% %~ Right brace. %^named_char \relax \if \mathmodep \zmrbrace \else \if \monoencodingp \char "7D\relax \else \PSbraceright \fi\fi} \let \} = \rbrace \def \registered {% %~ Registered symbol. %^named_char \ensurepar \PSregistered} \def \S {% %~ Section sign. %^named_char \ensurepar \PSsection} \def \SS {% %~ Double section sign. %^named_char \ensurepar \PSsection\PSsection} \chardef \ss = "19 %~ German eszett. \def \sterling {% %~ Pound sterling symbol. %^named_char \ensurepar \PSsterling} \def \tilde {% %~ Tilde. %^named_char \ensurepar \if \mathmodep \zmtilde \else \char "7E\relax \fi} \def \trademark {% %~ Trademark symbol. %^named_char \ensurepar \PStrademark} \def \underscore {% %~ Underscore. %^named_char \ensurepar \zprehyph{\underscorehyph}% \if \monoencodingp \char "5F\relax \else \PSunderscore \fi \zposthyph{\underscorehyph}} \let \_ = \underscore \def \udquote {% %~ Undirected double quote. %^named_char \ensurepar \if \monoencodingp \char "22\relax \else \PSudquote \fi} \def \usquote {% %~ Undirected single quote. %^named_char \ensurepar \if \monoencodingp \char "0D\relax \else \PSusquote \fi} \def \verticalbar {% %~ Vertical bar. %^named_char \ensurepar \if \monoencodingp \char "7C\relax \else \PSbar \fi} \def \|{% %~ Vertical bar. %^named_char \relax \if \mathmodep \Vert \else \verticalbar \fi} % Accents % ------- \def \"#1{{\accent "7F #1}} %~ Umlaut accent. %^accent \def \'#1{{\accent 19 #1}} %~ Acute accent. %^accent \def \.#1{{\accent 95 #1}} %~ Dot accent. %^accent \def \=#1{{\accent 22 #1}} %~ Macron accent. %^accent \def \^#1{{\accent 94 #1}} %~ Circumflex accent. %^accent \def \`#1{{\accent 18 #1}} %~ Grave accent. %^accent \def \~#1{{\accent "7E #1}} %~ Tilde accent. %^accent \def \b #1{% %~ Bar-under accent. %^accent \ozalign{\relax #1\cr \hidewidth \vbox to .2ex {\hbox{\char 22}\vss}\hidewidth}} \def \c #1{% %~ Cedilla accent. %^accent \setbox \zboxa = \hbox{#1}% \if \dimeqlp{\ht\zboxa}{1ex}% \accent 24 #1% \else {\ooalign{\hidewidth \char 24 \hidewidth \cr \unhbox \zboxa}}% \fi} \def \d #1{% %~ Dot-under accent. %^accent \ozalign{\relax #1\cr \hidewidth.\hidewidth}} \def \g #1{% %~ Ogonek accent. %^accent \setbox \zboxa = \hbox{#1}% \if \dimeqlp{\ht\zboxa}{1ex}% \accent 154 #1% \else {\ooalign{\hidewidth \char 154 \hidewidth \cr \unhbox \zboxa}}% \fi} \def \H #1{{\accent "7D #1}} %~ Long Hungarian umlaut accent. %^accent \def \r #1{{\accent "17 #1}} %~ Ring accent. %^accent \def \t #1{% %~ Tie-after accent. %^accent {\edef \znext {\the\font}\the\textfont1 \accent "7F \znext #1}} \def \u #1{{\accent 21 #1}} %~ Breve accent. %^accent \def \v #1{{\accent 20 #1}} %~ Hacek accent. %^accent % Spaces % ------ % TeX space primitives include the following: % % Produce a normal space, obeying \spacefactor. % \ Produce a normal space as if \spacefactor = 1000. % Here are a set of "space" commands that produce breakable space: %~ Specified amount of breakable horizontal space. \def \hspace #1{\ensurepar \hskip #1\relax}% {amount} %^hspace %~ Specified amount of unbreakable horizontal space %~ measured in tenths of a point. \def \h #1;{% tenths-points; %^hspace {\tdimena = .1pt \tdimena = #1\tdimena \kern \tdimena}} \def \fiveemspace {\ensurepar \hskip 5em\relax} %~ Breakable 5 em space. %^hspace \def \fouremspace {\ensurepar \hskip 4em\relax} %~ Breakable 4 em space. %^hspace \def \threeemspace {\ensurepar \hskip 3em\relax} %~ Breakable 3 em space. %^hspace \def \twoemspace {\ensurepar \hskip 2em\relax} %~ Breakable 2 em space. %^hspace \def \emspace {\ensurepar \hskip 1em\relax} %~ Breakable 1 em space. %^hspace \def \enspace {\ensurepar \hskip .5em\relax} %~ Breakable 1 en space. %^hspace \def \digitspace {% %~ Breakable digit space. %^hspace {\measuredigitwidth{\tdimena}% \ensurepar \hskip \tdimena}} {\catcode`\| = \catactive \gdef \digitspacebar {% \catcode`\| = \catactive \def |{\digitspace}} } \def \thirdspace {\ensurepar \hskip .333em\relax} %~ Breakable 1/3 em space. %^hspace \let \thickspace = \thirdspace \def \negthickspace {\ensurepar \hskip -.333em\relax} %~ Breakable negative 1/3 em space. %^hspace \def \space { } %~ Normal space. \def \^^M{\ } %~ Normal space. \def \fontspace {\ensurepar \hskip \fontdimen2\font} %~ Breakable font space. %^hspace \def \visiblespace {% %~ Visible space. %^hspace \ensurepar \hbox {% \measurespacewidth{\tdimena}% \kern .16ex \llap{\rule{width .08ex height .15ex depth .2ex}}% \lower .2ex \hbox{\rule{width \tdimena height .08ex depth 0pt}}% \rlap{\rule{width .08ex height .15ex depth .2ex}}% \kern .16ex}} \def \fourthspace {\ensurepar \hskip .25em\relax} %~ Breakable 1/4 em space. %^hspace \def \fifthspace {\ensurepar \hskip .2em\relax} %~ Breakable 1/5 em space. %^hspace \let \thinspace = \fifthspace \def \negfifthspace {\ensurepar \hskip -.2em\relax} %~ Breakable negative 1/3 em space. %^hspace \let \negthinspace = \negfifthspace \def \sixthspace {\ensurepar \hskip .16667em\relax} %~ Breakable 1/6 em space. %^hspace \def \negsixthspace {\ensurepar \hskip -.16667em\relax} %~ Breakable negative 1/6 em space. %^hspace \def \seventhspace {\ensurepar \hskip .14286em\relax} %~ Breakable 1/7 em space. %^hspace \let \hairspace = \seventhspace \def \negseventhspace {\ensurepar \hskip -.14286em\relax} %~ Breakable negative 1/7 em space. %^hspace \def \qqqqquad {\unbreakable\fiveemspace} %~ Unbreakable 5 em space. %^hspace \def \qqqquad {\unbreakable\fouremspace} %~ Unbreakable 4 em space. %^hspace \def \qqquad {\unbreakable\threeemspace} %~ Unbreakable 3 em space. %^hspace \def \qquad {\unbreakable\twoemspace} %~ Unbreakable 2 em space. %^hspace \def \quad {\unbreakable\emspace} %~ Unbreakable 1 em space. %^hspace \def \nut {\unbreakable\enspace} %~ Unbreakable 1 en space. %^hspace %~ Unbreakable 1/3 em space. \def \;{\relax\if \mathmodep \mthickspace \else \unbreakable\thickspace \fi} %^hspace %~ Unbreakable 1/5 em space. \def \,{\relax\if \mathmodep \mthinspace \else \unbreakable\thinspace \fi} %^hspace %~ Unbreakable negative 1/5 em space. \def \!{\relax\if \mathmodep \mnegthinspace \else \unbreakable\negthinspace\fi} %^hspace \def \+{\unbreakable\hairspace} %~ Unbreakable 1/7 em space. %^hspace %~ Specified amount of unbreakable horizontal space %~ measured in hundredths of an em. \def \k #1;{% hundredths-em; %^hspace {\tdimena = .01em \tdimena = #1\tdimena \kern \tdimena}} %~ This command retains horizontal space at the beginning of a line. %~ Such space is normally discarded. \def \retain {\vrule height 0pt depth 0pt width 0pt\relax} %^hspace %~ This declaration causes spaces to be "obeyed," so that every space %~ in the source is relevent. \def \obeyspaces {% \catcode`\ =\catactive} {\obeyspaces \global\let =\ % } % Space Factors % ----- ------- % IniTeX sets the space factor code of uppercase letters to 999 so % periods after them will not end sentences. That just gives people % one more rule to remember. \sfcode`\A=1000 \sfcode`\B=1000 \sfcode`\C=1000 \sfcode`\D=1000 \sfcode`\E=1000 \sfcode`\F=1000 \sfcode`\G=1000 \sfcode`\H=1000 \sfcode`\I=1000 \sfcode`\J=1000 \sfcode`\K=1000 \sfcode`\L=1000 \sfcode`\M=1000 \sfcode`\N=1000 \sfcode`\O=1000 \sfcode`\P=1000 \sfcode`\Q=1000 \sfcode`\R=1000 \sfcode`\S=1000 \sfcode`\T=1000 \sfcode`\U=1000 \sfcode`\V=1000 \sfcode`\W=1000 \sfcode`\X=1000 \sfcode`\Y=1000 \sfcode`\Z=1000 % A few characters should not affect the space factor. \sfcode`\'=0 \sfcode`\)=0 \sfcode`\]=0 \def \setsentencespacing #1{% {flag} \if #1% \sfcode`\. = 2250 \sfcode`\? = 2250 \sfcode`\! = 2250 \sfcode`\: = 2000 \else \sfcode`\. = 1000 \sfcode`\? = 1000 \sfcode`\! = 1000 \sfcode`\: = 1000 \fi \relax} % Numbers % ------- \let \lcromannumeral = \romannumeral %~ This command formats an integer as uppercase Roman numerals. \def \ucromannumeral #1{% {number} \uppercase\expandafter{\romannumeral#1}} %~ This command formats an integer as lowercase letters. \def \lcletter #1{% {number} \ifcase #1% 0\or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or k\or l\or m\or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or x\or y\or z\else \number#1\fi} %~ This command formats an integer as uppercase letters. \def \ucletter #1{% {number} \ifcase #1% 0\or A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or K\or L\or M\or N\or O\or P\or Q\or R\or S\or T\or U\or V\or W\or X\or Y\or Z\else \number#1\fi} % Lines % ----- \long\def \line #1{% {text} \if \vmodep {\parfillskip = 0pt \noindent #1\retain \par}% \else \retain #1\tl \fi} \long\def \leftline #1{\line{#1\hfil}}% {text} \long\def \rightline #1{\line{\hfil#1}}% {text} \long\def \centerline #1{\line{\hfil#1\hfil}}% {text} \long\def \spreadline #1#2{\line{{#1}\hfil{#2}}}% {text1}{text2} \long\def \centerspreadline #1#2#3{% \line{\rlap{#1}\hfil #2\hfil \llap{#3}}}% {text1}{text2}{text3} % This declaration causes line breaks to be "obeyed," so that each % results in a paragraph end. {\catcode`\^^M = \catactive% \gdef \obeylines {\catcode`\^^M = \active \let ^^M = \par}% } % Line Breaks % ---- ------ \def \linebreak #1{% {penalty} \penalty #1\relax} \def \tl {\break} \def \nl {% \gluevaries{\znlvar}{\leftskip}% \if \znlvar \tl \else \hfil \break \fi} \def \blankline {\ensurepar \nl} % These commands are used to tie text on one line. \def ~{\nobreak \ } % Unbreakable space (tie). \def \tie {\ensurepar \hbox} % Indentation % ----------- % Note that this macro just sets \leftskip and \rightskip, and so % blows away any \parrag. \def \setindentation #1#2{% {left}{right} \leftskip = #1\relax \rightskip = #2\relax} \def \alterindentation #1#2{% {left-delta}{right-delta} \leftskip = 1\leftskip \advance \leftskip by #1\relax \rightskip = 1\rightskip \advance \rightskip by #2\relax} % Text Width % ---- ----- % This command must be used AFTER the indentation is established with % \setindentation or \alterindentation. \def \settextwidth #1{% {width} \if \dimneqlp{#1}{\naturalwidth}% \hsize = #1\relax \advance \hsize by \leftskip \advance \hsize by \rightskip \fi} % Paragraph Raggedness % --------- ---------- % This command must be used AFTER the indentation is established with % \setindentation or \alterindentation. \def \setparrag #1{% {rag-dimen} \gluevaries{\zrsvar}{\rightskip}% \if \notp{\zrsvar}% \tdimena = #1\relax \advance \rightskip by 0pt plus \tdimena\relax \fi} \zdeclareeveryvcontext{\setindentation{0pt}{0pt}\setparrag{0pt}} % Paragraph Shapes % --------- ------ \definecount{\zshparct}{0} \definecount{\zshparrep}{0} \definedimen{\zshpari}{0pt} \definedimen{\zshparw}{0pt} \def \nshapepar #1{% {[*repeat1,]indent1,width1,...} \if \emptyargp{#1}% \error{empshape}{The argument to \string\shapepar cannot be empty}% \fi \gdef \zshpartoks {}% \global\zshparct = 0 {\zshapeparc #1,\zmark}% \parshape = \zshparct\zshpartoks\relax} \def \zshapeparc #1#2,#3\zmark{% [*repeat],indent,... \if \codeeqlp{#1}{*}% \global\zshparrep = #2\relax \def \znext {\zshapepare #3\zmark}% \else \global\zshparrep = 1 \def \znext {\zshapepare #1#2,#3\zmark}% \fi \znext} \def \zshapepare #1,#2,#3\zmark{% indent,width,... \zshapepard #1,\false,\zshpari\zmark \global\zshpari = \tdimena \zshapepard #2,\true,\zshparw\zmark \global\zshparw = \tdimena \loop \if \posp{\zshparrep}% \xdef \zshpartoks {\zshpartoks \space \the\zshpari \space \the\zshparw}% \global\increment \zshparct \global\decrement \zshparrep \repeat \if \emptyargp{#3}% \let \znext = \relax \else \def \znext {\zshapeparc #3\zmark}% \fi \znext} \def \zshapepard #1#2,#3,#4\zmark{% dimen1 dimen-rest,width?,prev \if \codeeqlp{#1}{+}% \calculate \tdimena = {#4,+,#2}% \else\if \codeeqlp{#1}{-}% \calculate \tdimena = {#4,-,#2}% \else\if \andp{\codeeqlp{#1}{=}}{#3}% \calculate \tdimena = {\hsize,-,\zshpari}% \else \tdimena = #1#2\relax \if \dimeqlp{\tdimena}{\naturalwidth}% \calculate \tdimena = {\hsize,-,\zshpari}% \fi \fi\fi\fi \if #3% %%% Do we want to adjust the width by \leftskip or \rightskip? \fi} %%%\definecount{\zshparct}{0} \definedimen{\zshpard}{0pt} \definedimen{\zshpare}{0pt} \def \shapepar #1{% {indent1,width1,...} \if \emptyargp{#1}% \error{empshape}{The argument to \string\shapepar cannot be empty}% \fi \gdef \zshpartoks {}% \global\zshparct = 0 {\zshapepara #1,\zmark}% \parshape = \zshparct\zshpartoks\relax} \def \zshapepara #1,#2,#3\zmark{% indent,width,...\zmark \zshpard = #1\relax \xdef \zshpartoks {\zshpartoks \space \the\zshpard}% \zshpare = #2\relax \if \dimeqlp{\zshpare}{\naturalwidth}% \zshpare = \hsize \advance \zshpare by -\zshpard \else \advance \zshpare by \leftskip \advance \zshpare by \rightskip \fi \xdef \zshpartoks {\zshpartoks \space \the\zshpare}% \global\increment \zshparct \if \emptyargp{#3}% \let \znext = \relax \else \def \znext {\zshapepara #3\zmark}% \fi \znext} \def \hangalign #1#2#3{% {indent}{text1}{text2} \endgraf {\setbox \zboxa = \hbox{#2}% \tdimena = \wd\zboxa \advance \tdimena by #1\relax \shapepar{#1,\naturalwidth,\tdimena,\naturalwidth}% \noindent \box\zboxa #3\par}} \def \hindent #1{% {indent} \noindent \hspace{#1}% \ignorespaces} % Adjustments % ----------- %~ This page overrides the number of lines in a paragraph. The argument %~ specifies the number of lines and should start with a plus or %~ minus sign. TeX does not guarantee the change. \def \overrideparlength #1{% {lines} %^page_makeup \looseness = #1\relax} %~ This command is used in the middle of a paragraph, on a line by %~ itself, to make an adjustment %~ between two lines. A typical use is to force a page break: %~ \adjustpar{\fullpagebreak} %~ There is no need to put a percent sign (|%|) after the command. \long\def \adjustpar #1{% {command} %^page_makeup \vadjust{#1}% \ignorespaces} % This command is used to adjust the title of a chapter, section, etc. % The argument looks like `\loc{commands}\loc{commands}...' % where each \loc is: % \body To adjust the title in the body of the text. % \mark To adjust the title in the mark (running heads and feet). % \toc To adjust the title in the table of contents. \def \zadjloc {\body} % Normally, \adjusttitle should adjust body. \def \adjusttitle #1{% {\loc{commands}...} {\def \body ##1{}% \def \mark ##1{}% \def \toc ##1{}% \expandafter\let \zadjloc = \zadjtitleb #1}} \def \zadjtitleb #1{% #1% \def \znext {#1}% \if \tokeqlp{\znext}{\nl}% \let \znext = \ignorespaces \else \let \znext = \relax \fi \znext} % These macros use \lspspace so they do the right thing while letterspacing. \def \titlenl {\adjusttitle{\body{\nl}}\lspspace} \def \titletl {\adjusttitle{\body{\tl}}\lspspace} \def \tocnl {\adjusttitle{\toc{\nl}}\lspspace} \def \toctl {\adjusttitle{\toc{\tl}}\lspspace} % These definitions are used by the new title adjustment scheme, % but need to be present even when it is not in use. \chardef \zadjtitlenone = 0 \chardef \zadjtitlebody = 1 \chardef \zadjtitlemark = 2 \chardef \zadjtitletoc = 3 \chardef \zadjtitleminitoc = 4 \definecount{\zadjtitle}{\zadjtitlebody}