Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

LaTeX defines in ltfssbas.dtx a macro called \strip@pt (at line [246]) which strips the pt part from a dimension returned by \the\dimension. The definition is shown as a minimal working example below:

\documentclass[11pt]{article} 
\begin{document}
\parindent=0pt
\makeatletter

\begingroup
  \catcode `P=12  % digits and punct. catcode
  \catcode `T=12  % digits and punct. catcode
  \lowercase{%
  \def\x{\def\rem@pt##1.##2PT{##1\ifnum##2>\z@.##2\fi}}}
     \expandafter\endgroup\x%
\def\strip@pt{\expandafter\rem@pt\the}

\newdimen\normallineskiplimit \normallineskiplimit=0.001pt

\texttt{Original dimen \the\normallineskiplimit}\\
\texttt{Stripped dimen \strip@pt\normallineskiplimit}\\

\makeatother
\end{document}

In the macro the catcode of the letters 'PT' are changed to category 12, which is the catcode for digits and punctuation. It then changes it to lowercase to match the pt returned by the \the\dimension. I can understand that the intent was to delimit the arguments with the PT returned by the \the\dimension, but why don't the lowercase letters work on their own? And a second question (pls \relax the one question limit). Just before the \def\strip@pt it writes \expandafter\endgroup\x. This could also be written as \x\endgroup and save the \expandafter. In the minimal I provided works both ways. Am I missing something?

share|improve this question
add comment

2 Answers

up vote 21 down vote accepted

On the 'PT' question, what is needed is the lower case tokens p and t with category code 12. As you say, \the<dimen> returns the value of the followed by pt, but these are 'other' tokens and not 'letters'. So something like

\def\rem@pt#1.#2pt{...

will not work, even with \lowercase (which changes character codes but not category codes): TeX would keep looking for the characters 'pt' with category code 'other', would probably not find them and would raise an error.

On the second question, \x\endgroup will only define \rem@pt inside the group you then close. You could use \gdef to get round this, but the \expandafter route also works as the content of \x is expanded outside of the group. Your example still compiles as the kernel has already globally defined \rem@pt. Try giving it a different name in your example and observe the 'Undefined control sequence error' that occurs when you expand \x before closing the group.


An alternative way to create the same macro but without using \lowercase is

\edef\rem@pt{%
  \def\noexpand\rem@pt##1.##2\string p\string t{%
    ##1\noexpand\ifnum##2>\noexpand\z@.##2\noexpand\fi
  }
}
\rem@pt

This works by creating the 'string' pt using the \string primitive (with e-TeX, you could also use \detokenize). The first definition for \rem@pt sets up for the second definition, which is then ultimately the same as the LaTeX kernel method.


A LaTeX3 implementation was requested in comments. At present, we have an internal function \__dim_strip_pt:n to do the job: this is very much in the same vein as the LaTeX2e code, but with dimension expression evaluation. The set up currently reads

\cs_new:Npn \__dim_strip_pt:n #1
  {
    \exp_after:wN
      \__dim_strip_pt:w \dim_use:N \__dim_eval:w #1 \__dim_eval_end: \q_stop
  }
\use:x
  {
    \cs_new:Npn \exp_not:N \__dim_strip_pt:w
      ##1 . ##2 \tl_to_str:n { pt } ##3 \exp_not:N \q_stop
      {
        ##1
        \exp_not:N \int_compare:nNnT {##2} > \c_zero
          { . ##2 }
      }
  }

where \dim_use:N \__dim_eval:w #1 \__dim_eval_end: is the same as \dim_eval:n but avoids needing to force expansion twice, which would be done using

\cs_new:Npn \__dim_strip_pt:n #1
   {
     \exp_after:wN \exp_after:wN \exp_after:wN
       \__dim_strip_pt:w \dim_eval:n {#1} \q_stop
   }

If there is a broader need for this 'strip the pt function then it can be moved from internal to general use. (It's intended to support driver-level code, which is written by the team and is therefore internal.)

share|improve this answer
    
Thanks! I guess the dimension is returned as category code 12 otherwise it would have been considered as two tokens? Your answer about the expandafter also makes perfect sense. Did try it out and is exactly as you say. Perfect answer on all counts. –  Yiannis Lazarides Nov 30 '10 at 20:17
    
@Yiannis. The 'pt' is two tokens whatever the category code. TeX usually spits things out as 'other' tokens rather than letters: try \romannumeral to see another case of this. I guess that the source for TeX will give more detail on the decision, but I suspect it's to ensure that the tokens don't accidentally end up as part of a preceding control sequence (if there is some \expandafter stuff on the go). –  Joseph Wright Nov 30 '10 at 20:21
    
Could you please give a LaTeX3 implementation of this macro? –  AlexG Dec 21 '12 at 13:04
    
@AlexG See edit. As you'll realise, the code currently set up is not intended for more general use as it's marked as 'internal', but that can easily be altered. Note that there is also a function for bp in the same vein. –  Joseph Wright Dec 21 '12 at 13:16
2  
\dim_strip_bp:n and \dim_strip_pt:n or even \dim_strip_in:n, \dim_strip_cm:n etc. would be highly welcome as public functions. –  AlexG Dec 21 '12 at 13:26
show 2 more comments

An alternative definition is used in ConTeXt which does not use that \lowercase trick. The following code is taken from syst-aux.mkiv.

%D \macros
%D   {withoutpt,PtToCm,
%D    numberofpoints,dimensiontocount}
%D
%D We can convert point into centimeters with:
%D
%D \starttyping
%D \PtToCm{dimension}
%D \stoptyping

{\catcode`\.=\othercatcode
 \catcode`\p=\othercatcode
 \catcode`\t=\othercatcode
 \gdef\WITHOUTPT#1pt{#1}}                                                                                                                                                                                      

\def\withoutpt#1%
  {\expandafter\WITHOUTPT#1}

%D The capitals are needed because \type{p} and \type{t} have
%D \CATCODE~12, while macronames only permit tokens with the
%D \CATCODE~11. As a result we cannot use the \type{.group}
%D primitives. Those who want to know more about this kind of
%D manipulations, we advice to study the \TEX book in detail.
%D Because this macro does not do any assignment, we can use it
%D in the following way too.

\def\PtToCm#1%
   {\withoutpt\the\dimexpr0.0351459804\dimexpr#1\relax\relax cm}

Unlike the LaTeX macro, this macro is not trying to truncate the digits after the decimal point and leaves it upto the user to add \the when needed.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.