diff options
Diffstat (limited to 'tex/context/base/spec-ini.mkii')
-rw-r--r-- | tex/context/base/spec-ini.mkii | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/tex/context/base/spec-ini.mkii b/tex/context/base/spec-ini.mkii new file mode 100644 index 000000000..0229a0e3d --- /dev/null +++ b/tex/context/base/spec-ini.mkii @@ -0,0 +1,559 @@ +%D \module +%D [ file=spec-ini, +%D version=1996.01.25, +%D title=\CONTEXT\ Special Macros, +%D subtitle=Initialization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA / Hans Hagen \& Ton Otten}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% todo: make this one more plain so that i can use it in plain jobs +% todo: no args, named vars instead +% maybe also drop multiple drivers and make simplify the default, then simplier defs + +\newif\ifsimplifyspecials \simplifyspecialstrue % see later + +%D We will forbid loading specials after the first page is +%D shipped out. + +\ifx\realpageno\undefined + \countdef\realpageno=0 \realpageno=1 +\fi + +%D Specials are \TEX's channel to the outside world. They make +%D \TEX\ even more platform independant and permit easy +%D adaption to new developments. One major drawback of specials +%D is that they have to be supported by printer drivers. We've +%D tried to overcome this problem by implementing specials as +%D a sort of drivers themselves. + +\writestatus{loading}{ConTeXt Special Macros / Initialization} + +\unprotect + +%D \TEX\ produces files in the \DVI\ format. This format is +%D well defined and stable. In this format one||byte commands +%D are used which can optionally be followed by length +%D specifiers and arguments. The \DVI||format incorporates a +%D channel to the outside world. This channel is activated by +%D the \TEX\ primitive \type {\special}. The sequence +%D +%D \starttyping +%D \special{Hello here I am.} +%D \stoptyping +%D +%D results in \DVI||codes: +%D +%D \starttyping +%D xxx1 16 Hello here I am. +%D \stoptyping +%D +%D The \type {xxx1} is represented in byte code 239 and the +%D number of following bytes in a~1, 2, 3 or~4 byte number. So +%D here we get $1+1+16$ bytes of code. +%D +%D Translating these codes is upto the \DVI\ driver. It's +%D common use to ignore specials that cannot be interpreted, so +%D the example string should have no consequences for the +%D output. + +%D \macros +%D {jobsuffix} +%D +%D By default, \TEX\ produces \DVI\ files which can be +%D converted to other filetypes. Sometimes it is handy to +%D know what the target file will be. In other driver +%D modules we wil set \type {\jobsuffix} to \type {pdf}. + +\def\jobsuffix{dvi} + +\def\setjobsuffix#1% + {\resetsystemmode\jobsuffix + \edef\jobsuffix{#1}% + \setsystemmode\jobsuffix} + +%D \macros +%D {everyresetspecials} +%D +%D Now what will this one do? We'll see in a few lines. + +\newtoks \everyresetspecials + +\appendtoksonce + \ifx\setjobsuffix\undefined\else\setjobsuffix{dvi}\fi +\to \everyresetspecials + +%D A rather fundamental difference between special and direct +%D settings is that the latter don't interfere with typesetting +%D but must be set before the first shipout, while the specials +%D must be packaged in the shipped out box in such a way that +%D they don't interfere. + +\newif\ifspecialbasedsettings \specialbasedsettingstrue + +\appendtoksonce + \specialbasedsettingstrue +\to \everyresetspecials + +%D Because there is no standardization in the use of specials, +%D more than one driver or program can be supported. The +%D specials are grouped in libraries. Some of these are +%D general, such as the \type{postscript} library, some are +%D tuned to a special kind of program, like the \type{pdf} +%D ones, and some support a specific driver, as we can see in +%D the \type{yandy} library. A library is build with the +%D commands: +%D +%D \starttyping +%D \startspecials[name][inheritance] +%D +%D \definespecial\none{...} +%D \definespecial\onlyone#1{...} +%D \definespecial\alot#1#2#3#4{...} +%D +%D \stopspecials +%D \stoptyping +%D +%D Because drivers can have overlap in low level macros, a +%D mechanism of inheritance is implemented. The libraries +%D defined as second argument are loaded first. +%D +%D Every special has to be predefined first. We do this with +%D the command: +%D +%D \starttyping +%D \installspecial [\none] [and] [0] +%D \installspecial [\onlyone] [and] [1] +%D \installspecial [\alot] [or] [4] +%D \stoptyping +%D +%D This means as much as: there is a special names +%D \type{\none} which has no arguments and has more than one +%D appearance. The special \type{\alot} on the other hand has +%D four arguments and is only defined once. Every instance in +%D the libraries of a special of category \type{and} is +%D executed when called upon, but only one special of +%D category \type{or} can be active. Most of the +%D \type{postscript}||specials are of category \type{or}, +%D because they tend to interfere with driver specific ones. +%D The interactive specials of \type{dviwindo} and \type{pdf} +%D are an example of specials that can be called both. +%D +%D A library is defined in a file with the name +%D \type{spec-...}. We load a library with the command: +%D +%D \starttyping +%D \usespecials [list] +%D \stoptyping +%D +%D where the list can contain one or more file tags, the +%D \type{...} in the filename. The keyword \type{reset} +%D resets all loaded specials. This is equivalent to +%D \type{\resetspecials}. + +%D Although a mechanism of nesting can be implemented, we +%D prefer to use a inheritance mechanism as mentioned. Calls +%D upon \type{\usespecials} within a \type{\startspecials} +%D would lead to confusion and errors. + +\newif\ifinheritspecials + +%D We define some local constants and variables. They look a +%D bit horrible but we don't want conflicts. + +\def\@@specfil@@{@@spcfil@@} +\def\@@speclst@@{@@spclst@@} +\def\@@speccat@@{@@spccat@@} +\def\@@specarg@@{@@spcarg@@} +\def\@@specexc@@{@@spcexc@@} + +% not faster +% +% \def\@@specfil@@{@sp@f@} +% \def\@@speclst@@{@sp@l@} +% \def\@@speccat@@{@sp@c@} +% \def\@@specarg@@{@sp@a@} +% \def\@@specexc@@{@sp@e@} + +\let\currentspecial \empty +\let\currentspecialfile\empty + +%D \macros +%D {startspecials} +%D +%D Every library has a unique name, which is given as the first +%D argument to \type{\startspecials}. When another library is +%D defined with the same name, previous specials can be +%D overruled. The name may differ from the file||tag. +%D +%D The optional second argument can consist of a list of +%D libraries that are to be loaded first. + +\def\dostartspecials[#1][#2]% + {\doifsomething{#2} + {\processcommalist[#2]\dousespecials}% + \doifelsenothing{#1} + {\let\currentspecial\s!unknown} + {\def\currentspecial{#1}}% + \unprotect} + +\def\startspecials + {\localpushmacro\currentspecial + \dodoubleempty\dostartspecials} + +\def\stopspecials + {\localpopmacro\currentspecial + \protect} + +%D \macros +%D {installspecial, +%D resetspecials} +%D +%D We have to install specials before we can define and use +%D them. The command itself is defined as a call to another +%D command that executes one or more user||defined specials, +%D depending of it's category: \type{or} versus \type{and}. +%D +%D The command \type{\installspecial} takes three +%D (non||optional) arguments: the name of the command, the +%D category it belongs to and the number of arguments it +%D takes. +%D +%D With \type{\resetspecials} we can unload the predefined +%D specials. Special reset actions |<|look in \type{spec-mis} +%D for an example|>| can be assigned to the token register +%D \type{\everyresetspecials}. + +\let\@@allspecials=\empty + +\def\doinstallspecial[#1][#2][#3]% + {\letvalue{\@@speclst@@\string#1}\empty + \setvalue{\@@speccat@@\string#1}{#2}% + \setvalue{\@@specarg@@\string#1}{#3}% + \addtocommalist{\string#1}\@@allspecials + \def#1{\executespecial#1}} + +\def\installspecial + {\dotripleargument\doinstallspecial} + +\def\resetspecials + {\the\everyresetspecials + \def\docommand##1% + {\letvalue{\@@speclst@@##1}\empty}% + \processcommacommand[\@@allspecials]\docommand} + +%D \macros +%D {definespecial} +%D +%D The command \type{\definespecial} take the place of +%D \type{\def} in the definition of a special. Just to be +%D sure, we first check if the command is permitted, i.e. +%D installed. If not, we give a warning and gobble the +%D illegal command in an quite elegant way. +%D +%D If the command can be combined (\type{and}) with others, +%D we append it to a list, otherwise (\type{or}) it becomes +%D the only item in the list. + +\def\definespecial#1% + {\ifx#1\undefined + \showmessage\m!specials4{\string#1}% + \def\next + {\def\@@illegalspecial@@}% + \else + \def\next + {\doifelsevalue{\@@speccat@@\string#1}{or} + {\edef\@@newspeclst@@{\currentspecial}} + {\edef\@@newspeclst@@{\getvalue{\@@speclst@@\string#1}}% + \addtocommalist\currentspecial\@@newspeclst@@}% + \setevalue{\@@speclst@@\string#1}{\@@newspeclst@@}% + \setvalue{\currentspecial\string#1}}% + \fi + \next} + +%D \macros +%D {usespecials} +%D +%D We use \type{\usespecials} to load a specific library. +%D This command is only permitted outside the definition part. + +\def\dousespecials#1% + {\doifelse{#1}\v!reset + {\resetspecials} + {\doifdefinedelse{\@@specfil@@#1} + {\edef\currentspecialfile{\getvalue{\@@specfil@@#1}}} + {\edef\currentspecialfile{#1}}% + \makeshortfilename[\truefilename{\f!specialprefix\currentspecialfile}]% + \startreadingfile + \readsysfile{\shortfilename.mkii}{\showmessage\m!specials5\currentspecialfile}\donothing + \stopreadingfile}} + +\def\usespecials[#1]% + {\ifnum\realpageno<2 + \doifelsenothing\currentspecial + {\processcommalist[#1]\dousespecials} + {\showmessage\m!specials6\empty}% + \fi} + +%D \macros +%D {executespecials} +%D +%D The command \type{\executespecials} is used to execute the +%D defined specials. Once a special is installed, the special +%D itself calls for this command, so it's not needed outside +%D this module. One can use it if wanted. +%D +%D A former implementation grouped the execution. Recent +%D additions however |<|like the specials that implement object +%D handling|>| asked for non||grouped execution. + +%D \starttyping +%D \def\executespecials#1#2% +%D {\def\doonespecial##1% +%D {\getvalue{##1\string#1}#2\relax}% +%D \processcommacommand +%D [\getvalue{\@@speclst@@\string#1}]\doonespecial} +%D +%D \def\executespecial#1% +%D {\expandafter\ifcase\getvalue{\@@specarg@@\string#1}\relax +%D \def\next% +%D {\executespecials#1{}}% +%D \or +%D \def\next##1% +%D {\executespecials#1{{##1}}}% +%D \or +%D \def\next##1##2% +%D {\executespecials#1{{##1}{##2}}}% +%D \or +%D \def\next##1##2##3% +%D {\executespecials#1{{##1}{##2}{##3}}}% +%D \or +%D \def\next##1##2##3##4% +%D {\executespecials#1{{##1}{##2}{##3}{##4}}}% +%D \or +%D \def\next##1##2##3##4##5% +%D {\executespecials#1{{##1}{##2}{##3}{##4}{##5}}}% +%D \or +%D \def\next##1##2##3##4##5##6% +%D {\executespecials#1{{##1}{##2}{##3}{##4}{##5}{##6}}}% +%D \or +%D \def\next##1##2##3##4##5##6##7% +%D {\executespecials#1{{##1}{##2}{##3}{##4}{##5}{##6}{##7}}}% +%D \or +%D \def\next##1##2##3##4##5##6##7##8% +%D {\executespecials#1{{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}}}% +%D \or +%D \def\next##1##2##3##4##5##6##7##8##9% +%D {\executespecials#1{{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}{##9}}}% +%D \else +%D \def\next% +%D {\message{illegal special: \string#1}}% +%D \fi +%D \next} +%D \stoptyping +%D +%D Because specials happen quite often, we will use a bit more +%D brute force. Keep in mind that we have to collect the +%D arguments because we want to support more drivers at once. +%D +%D I tested this on the next test. Where the previous alternative +%D took about 32 seconds, the new alternative takes 25 seconds. +%D +%D \starttyping +%D \testfeature{10000}{\setbox0=\hbox{test \color[red]{oeps} test}} +%D \stoptyping + +\def\@@exsp{exsp} + +\setvalue{\@@exsp0}{{}} +\setvalue{\@@exsp1}#1{{{#1}}} +\setvalue{\@@exsp2}#1#2{{{#1}{#2}}} +\setvalue{\@@exsp3}#1#2#3{{{#1}{#2}{#3}}} +\setvalue{\@@exsp4}#1#2#3#4{{{#1}{#2}{#3}{#4}}} +\setvalue{\@@exsp5}#1#2#3#4#5{{{#1}{#2}{#3}{#4}{#5}}} +\setvalue{\@@exsp6}#1#2#3#4#5#6{{{#1}{#2}{#3}{#4}{#5}{#6}}} +\setvalue{\@@exsp7}#1#2#3#4#5#6#7{{{#1}{#2}{#3}{#4}{#5}{#6}{#7}}} +\setvalue{\@@exsp8}#1#2#3#4#5#6#7#8{{{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}}} +\setvalue{\@@exsp9}#1#2#3#4#5#6#7#8#9{{{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}} + +%D \starttyping +%D \def\executespecials#1% +%D {\def\doonespecial##1% +%D {\csname##1\xspecialcommand\endcsname#1\relax}% +%D \@EA\rawprocesscommalist\@EA +%D [\csname\@@speclst@@\xspecialcommand\endcsname]\doonespecial} +%D +%D \def\executespecial#1% +%D {\def\xspecialcommand{\string#1}% +%D \@EA\@EA\@EA\executespecials\csname\@@exsp\csname\@@specarg@@\xspecialcommand\endcsname\endcsname} +%D \stoptyping + +%D Some more speed can be gained by using a dedicated string +%D processing routine. Now we can bring down the execution +%D time to 21 seconds, one third less than the original run time. + +\def\executespecials#1% + {\@EA\let\@EA\speciallist\csname\@@speclst@@\xspecialcommand\endcsname + \ifx\speciallist\empty\else + \def\doonespecial##1% + {\csname##1\xspecialcommand\endcsname#1\relax}% + \@EA\dodoonespecial\speciallist,\end,% + \fi} + +\def\executespecial#1% + {\def\xspecialcommand{\string#1}% + \@EA\@EA\@EA\executespecials\csname\@@exsp\csname\@@specarg@@\xspecialcommand\endcsname\endcsname} + +\def\dodoonespecial#1,% + {\ifx\end#1\else + \doonespecial{#1}\expandafter\dodoonespecial + \fi} + +%D This kind of saving only shows up when making interative +%D documents with lots of color switches. In such documents +%D tens of thousands of special calls are rather normal. +%D On a 650 Mhz Pentium, the previous test takes 15 seconds +%D less (on about 65 seconds). When processing 2000 page +%D interactive documents this saving can be neglected. + +%D In the previous macros, the \type{{{...}}} are needed +%D because we pass all those arguments to the specials support +%D macro. + +\let\openspecialfile \relax +\let\closespecialfile \relax + +%D \macros +%D {doifspecialavailableelse} +%D +%D For testing purposes (this was first needed when object +%D support was implemented) we have: +%D +%D \starttyping +%D \doifspecialavailableelse\specialcommand{true}{false} +%D \stoptyping +%D +%D e.g: +%D +%D \starttyping +%D \doifspecialavailableelse\doinsertobject{...}{...} +%D \stoptyping + +\def\doifspecialavailableelse#1#2#3% + {\doifelsevaluenothing{\@@speclst@@\string#1}{#3}{#2}} + +%D So far for the macros that deal with installing specials. +%D In the file \type {spec-def} you will find the predefined +%D specials. + +%D Now that we have seen the flexible way (permitting +%D special chains) we will implement a faster and flat +%D alternative. But only if flag si set. + +\ifsimplifyspecials + + \def\doinstallspecial[#1][#2][#3]% + {\appendtoks\forgetspecial#1{#3}\to\everyresetspecials + \@EA\chardef\csname\@@speclst@@\string#1\endcsname\zerocount + \forgetspecial#1{#3}} + + \def\forgetspecial#1#2% + {\ifcase#2\relax + \let#1\relax \or + \let#1\gobbleoneargument \or + \let#1\gobbletwoarguments \or + \let#1\gobblethreearguments \or + \let#1\gobblefourarguments \or + \let#1\gobblefivearguments \or + \let#1\gobblesixarguments \or + \let#1\gobblesevenarguments \or + \let#1\gobbleeightarguments \or + \let#1\gobbleninearguments \or + \let#1\gobbletenarguments \fi} + + \def\resetspecials + {\the\everyresetspecials} + + \def\definespecial#1% + {\@EA\chardef\csname\@@speclst@@\string#1\endcsname=1 + \def#1} + + \def\doifspecialavailableelse#1% + {\ifcase\csname\@@speclst@@\string#1\endcsname + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +\fi + +%D For quite some time the \CONTEXT\ way of specifying the +%D output format has been: +%D +%D \starttyping +%D \usespecials[ps,yy,win,pdf] +%D \stoptyping +%D +%D Because at \PRAGMA\ we use \DVIPSONE, this was a suitable +%D setting, but with \CONTEXT\ going public, the next sequence +%D is more suitable for \DVIPS\ users: +%D +%D \starttyping +%D \usespecials[reset,ps,tr,pdf] +%D \stoptyping +%D +%D On the other hand, for \PDFTEX\ we needed: +%D +%D \starttyping +%D \usespecials[tpd] +%D \stoptyping +%D +%D To simplify things, I decided to provide a higher level +%D command. +%D +%D \starttyping +%D \defineoutput[name][specials] +%D \setupoutput[name,...] +%D \stoptyping +%D +%D In a \type {spec-def} you can find some examples. + +\def\defineoutput + {\dodoubleargument\dodefineoutput} + +\def\dodefineoutput[#1][#2]% + {\setvalue{\??ui#1}{#2}} + +\def\dosetupoutput#1% + {\doifdefinedelse{\??ui#1} + {\processcommacommand[\getvalue{\??ui#1}]\dousespecials} + {\doifdefinedelse{\@@specfil@@#1} + {\dousespecials{#1}} + {\showmessage\m!specials7{#1}}}} + +% Beware, from now on changing the (default) driver files demands +% remaking the format (no big deal, since only i adapt the driver +% and need delayed loading). + +\let\currentoutput\empty + +\def\setupoutput[#1]% + {\doifnot{#1}{\currentoutput} + {\ifnum\realpageno<\plustwo % new + \resetspecials\processcommacommand[#1]\dosetupoutput + \edef\currentoutput{#1}% + \fi}} + +\def\preloadspecials % it's nicer to report this + {\doifsomething\currentoutput + {\showmessage\m!specials1\currentoutput}} + +\appendtoks + \savecurrentvalue\usedoutputdriver\currentoutput +\to \everyfirstshipout + +\protect \endinput |