# Typesetting URL/URI/IRI in plain TeX

I would like to be able to allow line breaking on /'s, ?, and &'s.

I understand I should change the \catcode's of those letters, but I don't want them to be global, but instead restricted to inside of the macro. This is what I have tried:

\def\url{%
\begingroup%
\def\urlaux##1{##1\endgroup}%
\catcode\&=13
\def&{\penalty0\char\&}%
\urlaux}

\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}
\bye


but TeX tells me that & is inaccessible on its \definition

I remember reading something like: “The catcode change is not being done during the execution of the macro, but during reading of it”, or something along those lines.

But I have tried moving the definition of the ampersand to inside of the \urlaux, for example, without success.

How could I make it accessible?

-
You need to alter the catcode when making the definition: here you've tokenized \url with & as the tab alignment char. – Joseph Wright May 15 '14 at 11:02
@Joseph: Yes, I've read that exact same sentence now a quadzillion times, yet I gain no insight from it as to how to proceed. – morbusg May 15 '14 at 11:05

TeX assigns category code when an argument is grabbed and tokenized. As a result, inside your definition of \url, & has catcode 'tab alignment' (assuming normal rules apply). You can only \def an active char, so this step fails as you've observed.

What you need to do is make sure that the definition of \url contains an active &:

\begingroup
\catcode\&=\active
\gdef\url{%
\begingroup%
\def\urlaux##1{##1\endgroup}%
\catcode\&=\active
% Catcode of & that is important here is when \url is defined:
\def&{\penalty0\char\&}%
\urlaux}
\endgroup

\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}
\bye


Notice that you still need to alter the catcode of & when grabbing the argument of \urlaux too! (The entire 'trick' here depends on not grabbing the argument using \url as that will tokenize at the wrong time.) That means that reordering to say

\begingroup
\catcode\&=\active
\gdef\url{%
\begingroup%
% Catcode of & that is important here is when \url is defined:
\def&{\penalty0\char\&}%
\def\urlaux##1{##1\endgroup}%
\catcode\&=\active
\urlaux}
\endgroup


will also work: the second catcode change is about the grabbed argument and has nothing to do with the definition of & that we are using.

-
Thanks! Though, am I right in arguing that \url has no argument? – morbusg May 15 '14 at 11:12
@morbusg Yes, I'll clarify – Joseph Wright May 15 '14 at 11:54

It is much better not to change catcodes mid document but instead change the mathcode (as then it works as much as possibe even in macro arguments) this is what url.sty does

url.sty uses hardly any latex so works with plain tex with a bit of encouragement, or you could simply edit the file to remove the latex bits rather than defining stubs as here

\catcode\@=11
\def\@namedef#1{\expandafter\def\csname#1\endcsname}
\def\@ifundefined#1#2#3{%
\expandafter\ifx\csname#1\endcsname\relax
#2\else#3\fi}
\let\protect\relax
\let\ProcessOptions\relax
\def\DeclareOption#1#2{}
\def\@makeother#1{\catcode#1=12 }
\def\@ifnextchar#1#2#3{#2}
\def\@empty{}
\def\@firstoftwo#1#2{#1}
\def\@secondoftwo#1#2{#2}
\newcount\@tempcnta
\input url.sty
\def\UrlFont{\tt}

\hrule

abc abc \url{http://www.example.com/one/two/three.html}  abc
abc abc \url{http://www.example.com/one/two/three.html}  abc
abc abc \url{http://www.example.com/one/two/three.html}  abc
abc abc \url{http://www.example.com/one/two/three.html}  abc
abc abc \url{http://www.example.com/one/two/three.html}  abc

\bye

-
Thanks. How does \mathcode come into play? – morbusg May 15 '14 at 12:43
Donald's trick in url.sty is to make characters by mathcode"8000 (same as ') which means then you can access their active definition without making them active. furthermore linebreaking is allowed with two differemt strengths eg at / and at . by making characters be \mathrel or \mathbin then the whole URL is set in inline math mode – David Carlisle May 15 '14 at 13:02

Use eplain:

\input eplain
\beginpackages
\usepackage{url}
\endpackages

\rightskip=10em minus 8em % avoid overfull box
\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}

\bye


Your (simplistic) definition can be corrected with

\begingroup
\catcode\&=\active % we want an active & in the replacement text of \url

\gdef\url{% \gdef because we're in a group
\begingroup
\def\urlaux##1{##1\endgroup}%
\catcode\&=\active
\def&{\penalty0\char\&}%
\urlaux}
\endgroup

\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}
\bye

-
I did try using url.sty via eplain, but I couldn't get it to work (I guess my other definitions somehow break it). But I didn't really need all the bling bling of the package, so I thought I'd just keep it really simple. Thanks, though! – morbusg May 15 '14 at 12:41

Package url can also be used with plain TeX via the help of miniltx:

\input miniltx.tex
\input url.sty
\resetatcatcode

\url{http://tex.stackexchange.com/questions/177340/typesetting-url-uri-iri-in-plain-tex}

\bye


-

The opmac package (intended for plainTeX) implements \url too:

\input opmac

\rightskip=0pt plus5em
\url{http://tex.stackexchange.com/some/long/path/and?someBizarreLong=param&andYetAnotherSuchBizarreLong=param}

\end


Of course, you needn't use whole opmac.tex but you can be inspired by the macro \url from it where you can see:

\def\url#1{{\def\tmpb{#1}%
\replacestrings{//}{{\urlskip\urlslashslash\urlbskip}}%
\replacestrings{/}{{\urlskip/\urlbskip}}%
\replacestrings{.}{{\urlskip.\urlbskip}}%
\replacestrings{?}{{\urlskip?\urlbskip}}%
\replacestrings{=}{{\urlskip=\urlbskip}}%
\replacestrings{~}{{\char\~}}%
\replacestrings{_}{{\char\_}}%
\replacestrings{^}{{\char\^}}%
\replacestrings{\\}{\bslash}%
\replacestrings{\{}{{\char\{}}%
\replacestrings{\}}{{\char\}}}%
\replacestrings{&}{{\urlbskip\char\& \urlskip}}%
}}


It means that the \url is implemetned by \replacestrings which is better than catcode changing because catcode changing does not work when whole \url{...} is a part of a parameter of another macro.

If you decided to do catcode manipulating then you can use \adef macro which is stolen from opmac.tex too:

\def\adef#1{\catcode#1=13 \bgroup \lccode\~=#1\lowercase{\egroup\def~}}

\def\url{%
\begingroup%
\adef&{\penalty0\char\&}%
\def\urlaux##1{##1\endgroup}%
\urlaux}
`

You can see that the catcode setting is more simple.

-