%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% latex.mp Parametrizable latex labels for metapost %% Copyright (c) 2003 JL Diaz %% based on an idea taken from Metafun, by Hans Hagen % % This program may be distributed and/or modified under the conditions % of the LaTeX Project Public License, either version 1.2 of this % license or (at your option) any later version. The latest version % of this license is in http://www.latex-project.org/lppl.txt and % version 1.2 or later is part of all distributions of LaTeX version % 1999/12/01 or later. % % This program consists of the file latex.mp %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % For the impatient: Jump to "USAGE" % % Introduction: The problem % % Let us suppose that you need to typeset several labels of the form % $x_1$, $x_2$, ... $x_{10}$. Since each label is a formula, the % construction btex/etex is required to typeset it through TeX (or % LaTeX). So, the straighforward solution is: % % label(btex $x_1$ etex, (1u,0u)); % label(btex $x_2$ etex, (2u,0u)); % ... % label(btex $x_{10}$ etex, (10u,0u)); % % This repeated structure is inviting us to convert it into a for % loop. A naive attempt would be: % % for i=1 upto 10: % label (btex $x_{i}$ etex, (i*u, 0)); % endfor; % % Unfortunately the above would produce ten times the same label % $x_{i}$, because i is not evaluated in this context as a variable. % % A second, more clever attempt would be: % % for i=1 upto 10: % label("btex $x_{" & decimal i & "}$ etex", (i*u, 0)); % endfor; % % where we are making use of the string concatenation operator (&), % and the "decimal" operator, which produces an string whith the % decimal representation of its argument. This way, the macro label % will receive successively as first argument the strings: "btex % $x_{1}$ etex", "btex $x_{2}$ etex", end so on. % % This solution does not work either, because label is receiving a % string, instead of a picture (which is the result of a proper % btex/etex construction). When a string is received, label simply % outputs that string, without calling TeX (LaTeX) for formatting it. % % Metapost provides a way of "executing" the code which is stored in % a string, it is the scantokens primitive. So, it appears that a % modification of the label primitive would be possible, which % applies the scantokens primitive on the string which it receives as % parameter. Unfortunately this does not work either, because the way % in which btex/etex works procludes it use as argument of % scantokens. % % So, apparently, there is not an easy solution to the problem of % passing arguments to the etex/btex construct. % % The solution % % Since the construct btex/etex can only be used at the "top level" % of a source file, and not embedded in any string, the only way to % achieve the desired result is to store the string "btex ... etex" % in an external temporal file, and input back that file. % % This solution is implemented in the macro package "TEX.mp" which is % part of the standard metapost distribution. Using this package, the % problem of printing the ten labels $x_1$ .. $x_{10}$ becomes simple: % % for i=0 upto 10: % label(TEX("$x_{" & decimal i & "}$", (u*i,0)); % endfor; % % The macro TEX receives an string as argument, and uses TeX to % typeset it. This is achieved, as already explained, by creating a % new string which encapsulated the given argument into a btex/etex % pair, writing this new string in an external file, and inputting % that file back. % % This approach has two main drawbacks: % % 1) An external file is created, and processed each time TEX is % used. This is very inefficient, and the slowdown is noticeable if % TEX is used often. % % 2) If we want to use latex istead of tex, the TEX macro will not % work, because the external file created through this macro does % not include the verbatimtex header required to initialize latex. % % Metafun approach: a clever solution % % In the excelent macro package Metafun (by Hans Hagens), a nice % solution is found to the first problem. Instead of writing the % auxiliar file and inputting it again, what is wrote is an auxiliar % metapost program which defines a serie of picture variables, each % one with the result of a btex/etex pair. In the first run of % metapost, this auxiliar file is write-only. In the second run, the % file is read at the beginning, so all picture variables get % defined. In this second run, each time the TEX macro is called, it % checks if the corresponding picture variable is already defined, % and in this case it simply returns its value. % % This approach is much more efficient, since a single externa file % is produced and processed, no matter how much the TEX macro is % called. The only drawback is that two metapost runs are required. % % latex.mp: my solution % % I liked very much the metafun solution, but I did not want to use % the whole Metafun package only to obtain this % functionality. Moreover, metafun relies in a set of external % scripts, which decide to input or not the external file, depending % on the existence of that file. I would prefer do not require perl % nor any other scripting language. Only metapost. % % This is why I wrote "latex.mp". It implements the idea in the % metafun package, but it does not require any external script in % order to check the existence of the auxiliar file. % % ================================================================ % % USAGE % % input "latex"; % initlatex(...); % ... % % latex("string to be formatted by latex"); % % Returns a picture which can be used in a label % % The initlatex macro writes a latex header in an auxiliar file. You % do not need to call this macro if you use TeX as typesetting engine. % % On the other hand, if you want to use LaTeX as typesetting engine, % you need to call this macro before the first beginfig(). The macro % requires a mandatory argument, which is a string with adittional % macro commands to be placed before the "\begin{document}". For % example: % % initlatex("\usepackage[latin1]{inputenc}\usepackage{amsmath}"); % % If you do not need any aditional package, you can use "" as % argument. % % You can use the latex macro in any place where a picture is % expected, as in the first argument of a label comand. For example: % % for i=0 upto 10: % label(latex("$x_{$ & decimal i & "}$", (u*i,0)); % endfor; % % In order to correctly obtain the labels which use the latex macro, % you need to process your source file twice through metapost. The % first run all labels will show as "[?]", but the second run they % will have the correct value. % % IMPORTANT: % % If the text passed to the latex macro contains errors, latex will be % unable to complete its run. This will make impossible to run mpost % on the source, even if the errors are corrected, until you delete % the auxiliar file (which has .mpt extension) % % %================================================================ % Implementation % numeric NumPic; % Total number of times that latex() macro has been % called picture LaTeXPic[]; % Picture array which stores the result of each % latex macro call. This array is filled when the % axiliar file is read. string LaTeXsetup; % additional packages and macro definitions for latex % Initialization NumPic:=0; LaTeXsetup:="\documentclass{article}"; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Entry point % % The auxiliar file is read, but only if it exists % if readfrom(jobname&".mpt") <> EOF: scantokens ("input "&jobname & ".mpt"); fi; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % initlatex() % % By calling this function, the user can specify aditional packages and % macro definitions to the be used by latex. % % For example: % % initlatex("\usepackage[latin1]{inputenc}\usepackage{amsmath}"); % % The global variable LaTeXsetup is also provided, mainly for third % party libraries which require to define their own macros. The % programmers of these libraries should append their own material to % the LaTeXsetup variable, by using the & operator. For example: % % LaTeXsetup:=LaTeXsetup & "\def\TO{\Longrightarrow}"; % def initlatex primary s = write "verbatimtex" to jobname & ".mpt"; write "%&latex" to jobname & ".mpt"; write LaTeXsetup to jobname & ".mpt"; write s to jobname & ".mpt"; write "\begin{document}" to jobname & ".mpt"; write "etex" to jobname & ".mpt"; enddef; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % latex() % % This macro receives a string, and returns a picture which contains % the result of running the string by latex. The result can be used % whenever a picture argument is expected, as for example in a label. vardef latex@#(expr txt) = NumPic := NumPic + 1 ; if string txt : write "% figure " & decimal charcode & " : " & char(10) & "LaTeXPic[" & decimal NumPic & "] := btex " & txt & " etex ;" to jobname & ".mpt" ; if unknown LaTeXPic[NumPic] : thelabel@#("[??]",origin) else : thelabel@#(LaTeXPic[NumPic],origin) fi else : thelabel@#(txt,origin) fi enddef ; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % EOF