1146515Sru/* xref.c -- cross references for Texinfo.
2146515Sru   $Id: xref.c,v 1.4 2004/12/21 17:28:35 karl Exp $
3146515Sru
4146515Sru   Copyright (C) 2004 Free Software Foundation, Inc.
5146515Sru
6146515Sru   This program is free software; you can redistribute it and/or modify
7146515Sru   it under the terms of the GNU General Public License as published by
8146515Sru   the Free Software Foundation; either version 2, or (at your option)
9146515Sru   any later version.
10146515Sru
11146515Sru   This program is distributed in the hope that it will be useful,
12146515Sru   but WITHOUT ANY WARRANTY; without even the implied warranty of
13146515Sru   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14146515Sru   GNU General Public License for more details.
15146515Sru
16146515Sru   You should have received a copy of the GNU General Public License
17146515Sru   along with this program; if not, write to the Free Software Foundation,
18146515Sru   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19146515Sru
20146515Sru#include "system.h"
21146515Sru#include "cmds.h"
22146515Sru#include "float.h"
23146515Sru#include "html.h"
24146515Sru#include "index.h"
25146515Sru#include "macro.h"
26146515Sru#include "makeinfo.h"
27146515Sru#include "node.h"
28146515Sru#include "xml.h"
29146515Sru#include "xref.h"
30146515Sru
31146515Sru/* Flags which control initial output string for xrefs. */
32146515Sruint px_ref_flag = 0;
33146515Sruint ref_flag = 0;
34146515Sru
35146515Sru/* Called in the multiple-argument case to make sure we generate a valid
36146515Sru   Info reference.  In the single-argument case, the :: we output
37146515Sru   suffices for the Info readers to find the end of the reference.  */
38146515Srustatic void
39146515Sruadd_xref_punctuation (void)
40146515Sru{
41146515Sru  if (px_ref_flag || ref_flag)  /* user inserts punct after @xref */
42146515Sru    {
43146515Sru      /* Check if there's already punctuation.  */
44146515Sru      int next_char = next_nonwhitespace_character ();
45146515Sru
46146515Sru      if (next_char == -1)
47146515Sru        /* EOF while looking for punctuation, let's
48146515Sru           insert a period instead of crying.  */
49146515Sru        add_char ('.');
50146515Sru      else if (next_char != ',' && next_char != '.')
51146515Sru        /* period and comma terminate xrefs, and nothing else.  Instead
52146515Sru           of generating an Info reference that can't be followed,
53146515Sru           though, just insert a period.  Not pretty, but functional.  */
54146515Sru        add_char ('.');
55146515Sru    }
56146515Sru}
57146515Sru
58146515Sru/* Return next comma-delimited argument, but do not cross a close-brace
59146515Sru   boundary.  Clean up whitespace, too.  If EXPAND is nonzero, replace
60146515Sru   the entire brace-delimited argument list with its expansion before
61146515Sru   looking for the next comma.  */
62146515Sruchar *
63146515Sruget_xref_token (int expand)
64146515Sru{
65146515Sru  char *string = 0;
66146515Sru
67146515Sru  if (docbook)
68146515Sru    xml_in_xref_token = 1;
69146515Sru
70146515Sru  if (expand)
71146515Sru    {
72146515Sru      int old_offset = input_text_offset;
73146515Sru      int old_lineno = line_number;
74146515Sru
75146515Sru      get_until_in_braces ("}", &string);
76146515Sru      if (curchar () == '}')    /* as opposed to end of text */
77146515Sru        input_text_offset++;
78146515Sru      if (input_text_offset > old_offset)
79146515Sru        {
80146515Sru          int limit = input_text_offset;
81146515Sru
82146515Sru          input_text_offset = old_offset;
83146515Sru          line_number = old_lineno;
84146515Sru          only_macro_expansion++;
85146515Sru          replace_with_expansion (input_text_offset, &limit);
86146515Sru          only_macro_expansion--;
87146515Sru        }
88146515Sru      free (string);
89146515Sru    }
90146515Sru
91146515Sru  get_until_in_braces (",", &string);
92146515Sru  if (curchar () == ',')
93146515Sru    input_text_offset++;
94146515Sru  fix_whitespace (string);
95146515Sru
96146515Sru  if (docbook)
97146515Sru    xml_in_xref_token = 0;
98146515Sru
99146515Sru  return string;
100146515Sru}
101146515Sru
102146515Sru
103146515Sru/* NOTE: If you wonder why the HTML output is produced with such a
104146515Sru   peculiar mix of calls to add_word and execute_string, here's the
105146515Sru   reason.  get_xref_token (1) expands all macros in a reference, but
106146515Sru   any other commands, like @value, @@, etc., are left intact.  To
107146515Sru   expand them, we need to run the arguments through execute_string.
108146515Sru   However, characters like <, &, > and others cannot be let into
109146515Sru   execute_string, because they will be escaped.  See the mess?  */
110146515Sru
111146515Sru/* Make a cross reference. */
112146515Sruvoid
113146515Srucm_xref (int arg)
114146515Sru{
115146515Sru  if (arg == START)
116146515Sru    {
117146515Sru      char *arg1 = get_xref_token (1); /* expands all macros in xref */
118146515Sru      char *arg2 = get_xref_token (0);
119146515Sru      char *arg3 = get_xref_token (0);
120146515Sru      char *arg4 = get_xref_token (0);
121146515Sru      char *arg5 = get_xref_token (0);
122146515Sru      char *tem;
123146515Sru
124146515Sru      /* "@xref{,Foo,, Bar, Baz} is not valid usage of @xref.  The
125146515Sru         first argument must never be blank." --rms.
126146515Sru         We hereby comply by disallowing such constructs.  */
127146515Sru      if (!*arg1)
128146515Sru        line_error (_("First argument to cross-reference may not be empty"));
129146515Sru
130146515Sru      if (docbook)
131146515Sru        {
132146515Sru          if (!ref_flag)
133146515Sru            add_word (px_ref_flag || printing_index
134146515Sru                ? (char *) _("see ") : (char *) _("See "));
135146515Sru
136146515Sru          if (!*arg4 && !*arg5)
137146515Sru            {
138146515Sru              char *arg1_id = xml_id (arg1);
139146515Sru
140146515Sru              if (*arg2 || *arg3)
141146515Sru                {
142146515Sru                  xml_insert_element_with_attribute (XREFNODENAME, START,
143146515Sru                                                     "linkend=\"%s\"", arg1_id);
144146515Sru                  free (arg1_id);
145146515Sru                  execute_string ("%s", *arg3 ? arg3 : arg2);
146146515Sru                  xml_insert_element (XREFNODENAME, END);
147146515Sru                }
148146515Sru              else
149146515Sru                {
150146515Sru                  xml_insert_element_with_attribute (XREF, START,
151146515Sru                                                     "linkend=\"%s\"", arg1_id);
152146515Sru                  xml_insert_element (XREF, END);
153146515Sru                  free (arg1_id);
154146515Sru                }
155146515Sru            }
156146515Sru          else if (*arg5)
157146515Sru            {
158146515Sru              add_word_args (_("See section ``%s'' in "), *arg3 ? arg3 : arg1);
159146515Sru              xml_insert_element (CITE, START);
160146515Sru              add_word (arg5);
161146515Sru              xml_insert_element (CITE, END);
162146515Sru            }
163146515Sru          else if (*arg4)
164146515Sru            {
165146515Sru              /* Very sad, we are losing xrefs made to ``info only'' books.  */
166146515Sru            }
167146515Sru        }
168146515Sru      else if (xml)
169146515Sru        {
170146515Sru          if (!ref_flag)
171146515Sru            add_word_args ("%s", px_ref_flag ? _("see ") : _("See "));
172146515Sru
173146515Sru          xml_insert_element (XREF, START);
174146515Sru          xml_insert_element (XREFNODENAME, START);
175146515Sru          execute_string ("%s", arg1);
176146515Sru          xml_insert_element (XREFNODENAME, END);
177146515Sru          if (*arg2)
178146515Sru            {
179146515Sru              xml_insert_element (XREFINFONAME, START);
180146515Sru              execute_string ("%s", arg2);
181146515Sru              xml_insert_element (XREFINFONAME, END);
182146515Sru            }
183146515Sru          if (*arg3)
184146515Sru            {
185146515Sru              xml_insert_element (XREFPRINTEDDESC, START);
186146515Sru              execute_string ("%s", arg3);
187146515Sru              xml_insert_element (XREFPRINTEDDESC, END);
188146515Sru            }
189146515Sru          if (*arg4)
190146515Sru            {
191146515Sru              xml_insert_element (XREFINFOFILE, START);
192146515Sru              execute_string ("%s", arg4);
193146515Sru              xml_insert_element (XREFINFOFILE, END);
194146515Sru            }
195146515Sru          if (*arg5)
196146515Sru            {
197146515Sru              xml_insert_element (XREFPRINTEDNAME, START);
198146515Sru              execute_string ("%s", arg5);
199146515Sru              xml_insert_element (XREFPRINTEDNAME, END);
200146515Sru            }
201146515Sru          xml_insert_element (XREF, END);
202146515Sru        }
203146515Sru      else if (html)
204146515Sru        {
205146515Sru          if (!ref_flag)
206146515Sru            add_word_args ("%s", px_ref_flag ? _("see ") : _("See "));
207146515Sru        }
208146515Sru      else
209146515Sru        add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
210146515Sru
211146515Sru      if (!xml)
212146515Sru        {
213146515Sru          if (*arg5 || *arg4)
214146515Sru            {
215146515Sru              /* arg1 - node name
216146515Sru                 arg2 - reference name
217146515Sru                 arg3 - title or topic (and reference name if arg2 is NULL)
218146515Sru                 arg4 - info file name
219146515Sru                 arg5 - printed manual title  */
220146515Sru              char *ref_name;
221146515Sru
222146515Sru              if (!*arg2)
223146515Sru                {
224146515Sru                  if (*arg3)
225146515Sru                    ref_name = arg3;
226146515Sru                  else
227146515Sru                    ref_name = arg1;
228146515Sru                }
229146515Sru              else
230146515Sru                ref_name = arg2;
231146515Sru
232146515Sru              if (html)
233146515Sru                { /* More to do eventually, down to Unicode
234146515Sru                     Normalization Form C.  See the HTML Xref nodes in
235146515Sru                     the manual.  */
236146515Sru                  char *file_arg = arg4;
237146515Sru                  add_html_elt ("<a href=");
238146515Sru
239146515Sru                  {
240146515Sru                    /* If there's a directory part, ignore it.  */
241146515Sru                    char *p = strrchr (file_arg, '/');
242146515Sru                    if (p)
243146515Sru                      file_arg = p + 1;
244146515Sru
245146515Sru                  /* If there's a dot, make it a NULL terminator, so the
246146515Sru                     extension does not get into the way.  */
247146515Sru                    p = strrchr (file_arg , '.');
248146515Sru                    if (p != NULL)
249146515Sru                      *p = 0;
250146515Sru                  }
251146515Sru
252146515Sru                  if (! *file_arg)
253146515Sru                warning (_("Empty file name for HTML cross reference in `%s'"),
254146515Sru                           arg4);
255146515Sru
256146515Sru                  /* Note that if we are splitting, and the referenced
257146515Sru                     tag is an anchor rather than a node, we will
258146515Sru                     produce a reference to a file whose name is
259146515Sru                     derived from the anchor name.  However, only
260146515Sru                     nodes create files, so we are referencing a
261146515Sru                     non-existent file.  cm_anchor, which see, deals
262146515Sru                     with that problem.  */
263146515Sru                  if (splitting)
264146515Sru                    execute_string ("\"../%s/", file_arg);
265146515Sru                  else
266146515Sru                    execute_string ("\"%s.html", file_arg);
267146515Sru                  /* Do not collapse -- to -, etc., in references.  */
268146515Sru                  in_fixed_width_font++;
269146515Sru                  tem = expansion (arg1, 0); /* expand @-commands in node */
270146515Sru                  in_fixed_width_font--;
271146515Sru                  add_anchor_name (tem, 1);
272146515Sru                  free (tem);
273146515Sru                  add_word ("\">");
274146515Sru                  execute_string ("%s",ref_name);
275146515Sru                  add_word ("</a>");
276146515Sru                }
277146515Sru              else
278146515Sru                {
279146515Sru                  execute_string ("%s:", ref_name);
280146515Sru                  in_fixed_width_font++;
281146515Sru                  execute_string (" (%s)%s", arg4, arg1);
282146515Sru                  add_xref_punctuation ();
283146515Sru                  in_fixed_width_font--;
284146515Sru                }
285146515Sru
286146515Sru              /* Free all of the arguments found. */
287146515Sru              if (arg1) free (arg1);
288146515Sru              if (arg2) free (arg2);
289146515Sru              if (arg3) free (arg3);
290146515Sru              if (arg4) free (arg4);
291146515Sru              if (arg5) free (arg5);
292146515Sru              return;
293146515Sru            }
294146515Sru          else
295146515Sru            remember_node_reference (arg1, line_number, followed_reference);
296146515Sru
297146515Sru          if (*arg3)
298146515Sru            {
299146515Sru              if (html)
300146515Sru                {
301146515Sru                  add_html_elt ("<a href=\"");
302146515Sru                  in_fixed_width_font++;
303146515Sru                  tem = expansion (arg1, 0);
304146515Sru                  in_fixed_width_font--;
305146515Sru                  add_anchor_name (tem, 1);
306146515Sru                  free (tem);
307146515Sru                  add_word ("\">");
308146515Sru                  execute_string ("%s", *arg2 ? arg2 : arg3);
309146515Sru                  add_word ("</a>");
310146515Sru                }
311146515Sru              else
312146515Sru                {
313146515Sru                  execute_string ("%s:", *arg2 ? arg2 : arg3);
314146515Sru                  in_fixed_width_font++;
315146515Sru                  execute_string (" %s", arg1);
316146515Sru                  add_xref_punctuation ();
317146515Sru                  in_fixed_width_font--;
318146515Sru                }
319146515Sru            }
320146515Sru          else
321146515Sru            {
322146515Sru              if (html)
323146515Sru                {
324146515Sru                  add_html_elt ("<a href=\"");
325146515Sru                  in_fixed_width_font++;
326146515Sru                  tem = expansion (arg1, 0);
327146515Sru                  in_fixed_width_font--;
328146515Sru                  add_anchor_name (tem, 1);
329146515Sru                  free (tem);
330146515Sru                  add_word ("\">");
331146515Sru                  if (*arg2)
332146515Sru                    execute_string ("%s", arg2);
333146515Sru                  else
334146515Sru                    {
335146515Sru                      char *fref = get_float_ref (arg1);
336146515Sru                      execute_string ("%s", fref ? fref : arg1);
337146515Sru                      free (fref);
338146515Sru                    }
339146515Sru                  add_word ("</a>");
340146515Sru                }
341146515Sru              else
342146515Sru                {
343146515Sru                  if (*arg2)
344146515Sru                    {
345146515Sru                      execute_string ("%s:", arg2);
346146515Sru                      in_fixed_width_font++;
347146515Sru                      execute_string (" %s", arg1);
348146515Sru                      add_xref_punctuation ();
349146515Sru                      in_fixed_width_font--;
350146515Sru                    }
351146515Sru                  else
352146515Sru                    {
353146515Sru                      char *fref = get_float_ref (arg1);
354146515Sru                      if (fref)
355146515Sru                        { /* Reference is being made to a float.  */
356146515Sru                          execute_string ("%s:", fref);
357146515Sru                          in_fixed_width_font++;
358146515Sru                          execute_string (" %s", arg1);
359146515Sru                          add_xref_punctuation ();
360146515Sru                          in_fixed_width_font--;
361146515Sru                        }
362146515Sru                      else
363146515Sru                        {
364146515Sru                          in_fixed_width_font++;
365146515Sru                          execute_string ("%s::", arg1);
366146515Sru                          in_fixed_width_font--;
367146515Sru                        }
368146515Sru                    }
369146515Sru                }
370146515Sru            }
371146515Sru        }
372146515Sru      /* Free all of the arguments found. */
373146515Sru      if (arg1) free (arg1);
374146515Sru      if (arg2) free (arg2);
375146515Sru      if (arg3) free (arg3);
376146515Sru      if (arg4) free (arg4);
377146515Sru      if (arg5) free (arg5);
378146515Sru    }
379146515Sru  else
380146515Sru    { /* Check that the next non-whitespace character is valid to follow
381146515Sru         an xref (so Info readers can find the node names).
382146515Sru         `input_text_offset' is pointing at the "}" which ended the xref
383146515Sru         command.  This is not used for @pxref or @ref, since we insert
384146515Sru         the necessary punctuation above, if needed.  */
385146515Sru      int temp = next_nonwhitespace_character ();
386146515Sru
387146515Sru      if (temp == -1)
388146515Sru        warning (_("End of file reached while looking for `.' or `,'"));
389146515Sru      else if (temp != '.' && temp != ',')
390146515Sru        warning (_("`.' or `,' must follow @%s, not `%c'"), command, temp);
391146515Sru    }
392146515Sru}
393146515Sru
394146515Sruvoid
395146515Srucm_pxref (int arg)
396146515Sru{
397146515Sru  if (arg == START)
398146515Sru    {
399146515Sru      px_ref_flag++;
400146515Sru      cm_xref (arg);
401146515Sru      px_ref_flag--;
402146515Sru    }
403146515Sru  /* cm_xref isn't called with arg == END, which disables the code near
404146515Sru     the end of cm_xref that checks for `.' or `,' after the
405146515Sru     cross-reference.  This is because cm_xref generates the required
406146515Sru     character itself (when needed) if px_ref_flag is set.  */
407146515Sru}
408146515Sru
409146515Sruvoid
410146515Srucm_ref (int arg)
411146515Sru{
412146515Sru  /* See the comments in cm_pxref about the checks for punctuation.  */
413146515Sru  if (arg == START)
414146515Sru    {
415146515Sru      ref_flag++;
416146515Sru      cm_xref (arg);
417146515Sru      ref_flag--;
418146515Sru    }
419146515Sru}
420146515Sru
421146515Sruvoid
422146515Srucm_inforef (int arg)
423146515Sru{
424146515Sru  if (arg == START)
425146515Sru    {
426146515Sru      char *node = get_xref_token (1); /* expands all macros in inforef */
427146515Sru      char *pname = get_xref_token (0);
428146515Sru      char *file = get_xref_token (0);
429146515Sru
430146515Sru      /* (see comments at cm_xref).  */
431146515Sru      if (!*node)
432146515Sru        line_error (_("First argument to @inforef may not be empty"));
433146515Sru
434146515Sru      if (xml && !docbook)
435146515Sru        {
436146515Sru          xml_insert_element (INFOREF, START);
437146515Sru          xml_insert_element (INFOREFNODENAME, START);
438146515Sru          execute_string ("%s", node);
439146515Sru          xml_insert_element (INFOREFNODENAME, END);
440146515Sru          if (*pname)
441146515Sru            {
442146515Sru              xml_insert_element (INFOREFREFNAME, START);
443146515Sru              execute_string ("%s", pname);
444146515Sru              xml_insert_element (INFOREFREFNAME, END);
445146515Sru            }
446146515Sru          xml_insert_element (INFOREFINFONAME, START);
447146515Sru          execute_string ("%s", file);
448146515Sru          xml_insert_element (INFOREFINFONAME, END);
449146515Sru
450146515Sru          xml_insert_element (INFOREF, END);
451146515Sru        }
452146515Sru      else if (html)
453146515Sru        {
454146515Sru          char *tem;
455146515Sru
456146515Sru          add_word ((char *) _("see "));
457146515Sru          /* html fixxme: revisit this */
458146515Sru          add_html_elt ("<a href=");
459146515Sru          if (splitting)
460146515Sru            execute_string ("\"../%s/", file);
461146515Sru          else
462146515Sru            execute_string ("\"%s.html", file);
463146515Sru          tem = expansion (node, 0);
464146515Sru          add_anchor_name (tem, 1);
465146515Sru          add_word ("\">");
466146515Sru          execute_string ("%s", *pname ? pname : tem);
467146515Sru          add_word ("</a>");
468146515Sru          free (tem);
469146515Sru        }
470146515Sru      else
471146515Sru        {
472146515Sru          if (*pname)
473146515Sru            execute_string ("*note %s: (%s)%s", pname, file, node);
474146515Sru          else
475146515Sru            execute_string ("*note (%s)%s::", file, node);
476146515Sru        }
477146515Sru
478146515Sru      free (node);
479146515Sru      free (pname);
480146515Sru      free (file);
481146515Sru    }
482146515Sru}
483146515Sru
484146515Sru/* A URL reference.  */
485146515Sruvoid
486146515Srucm_uref (int arg)
487146515Sru{
488146515Sru  if (arg == START)
489146515Sru    {
490146515Sru      extern int printing_index;
491146515Sru      char *url  = get_xref_token (1); /* expands all macros in uref */
492146515Sru      char *desc = get_xref_token (0);
493146515Sru      char *replacement = get_xref_token (0);
494146515Sru
495146515Sru      if (docbook)
496146515Sru        {
497146515Sru          xml_insert_element_with_attribute (UREF, START, "url=\"%s\"",
498146515Sru              text_expansion (url));
499146515Sru          if (*replacement)
500146515Sru            execute_string ("%s", replacement);
501146515Sru          else if (*desc)
502146515Sru            execute_string ("%s", desc);
503146515Sru          else
504146515Sru            execute_string ("%s", url);
505146515Sru          xml_insert_element (UREF, END);
506146515Sru        }
507146515Sru      else if (xml)
508146515Sru        {
509146515Sru          xml_insert_element (UREF, START);
510146515Sru          xml_insert_element (UREFURL, START);
511146515Sru          execute_string ("%s", url);
512146515Sru          xml_insert_element (UREFURL, END);
513146515Sru          if (*desc)
514146515Sru            {
515146515Sru              xml_insert_element (UREFDESC, START);
516146515Sru              execute_string ("%s", desc);
517146515Sru              xml_insert_element (UREFDESC, END);
518146515Sru            }
519146515Sru          if (*replacement)
520146515Sru            {
521146515Sru              xml_insert_element (UREFREPLACEMENT, START);
522146515Sru              execute_string ("%s", replacement);
523146515Sru              xml_insert_element (UREFREPLACEMENT, END);
524146515Sru            }
525146515Sru          xml_insert_element (UREF, END);
526146515Sru        }
527146515Sru      else if (html)
528146515Sru        { /* never need to show the url */
529146515Sru          add_html_elt ("<a href=");
530146515Sru          /* don't collapse `--' etc. in the url */
531146515Sru          in_fixed_width_font++;
532146515Sru          execute_string ("\"%s\"", url);
533146515Sru          in_fixed_width_font--;
534146515Sru          add_word (">");
535146515Sru          execute_string ("%s", *replacement ? replacement
536146515Sru                                : (*desc ? desc : url));
537146515Sru          add_word ("</a>");
538146515Sru        }
539146515Sru      else if (*replacement) /* do not show the url */
540146515Sru        execute_string ("%s", replacement);
541146515Sru      else if (*desc)        /* show both text and url */
542146515Sru        {
543146515Sru          execute_string ("%s ", desc);
544146515Sru          in_fixed_width_font++;
545146515Sru          execute_string ("(%s)", url);
546146515Sru          in_fixed_width_font--;
547146515Sru        }
548146515Sru      else /* no text at all, so have the url to show */
549146515Sru        {
550146515Sru          in_fixed_width_font++;
551146515Sru          execute_string ("%s%s%s",
552146515Sru                          printing_index ? "" : "`",
553146515Sru                          url,
554146515Sru                          printing_index ? "" : "'");
555146515Sru          in_fixed_width_font--;
556146515Sru        }
557146515Sru      if (url)
558146515Sru        free (url);
559146515Sru      if (desc)
560146515Sru        free (desc);
561146515Sru      if (replacement)
562146515Sru        free (replacement);
563146515Sru    }
564146515Sru}
565146515Sru
566146515Sru/* An email reference.  */
567146515Sruvoid
568146515Srucm_email (int arg)
569146515Sru{
570146515Sru  if (arg == START)
571146515Sru    {
572146515Sru      char *addr = get_xref_token (1); /* expands all macros in email */
573146515Sru      char *name = get_xref_token (0);
574146515Sru
575146515Sru      if (xml && docbook)
576146515Sru        {
577146515Sru          xml_insert_element_with_attribute (EMAIL, START, "url=\"mailto:%s\"", addr);
578146515Sru          if (*name)
579146515Sru              execute_string ("%s", name);
580146515Sru          xml_insert_element (EMAIL, END);
581146515Sru        }
582146515Sru      else if (xml)
583146515Sru        {
584146515Sru          xml_insert_element (EMAIL, START);
585146515Sru          xml_insert_element (EMAILADDRESS, START);
586146515Sru          execute_string ("%s", addr);
587146515Sru          xml_insert_element (EMAILADDRESS, END);
588146515Sru          if (*name)
589146515Sru            {
590146515Sru              xml_insert_element (EMAILNAME, START);
591146515Sru              execute_string ("%s", name);
592146515Sru              xml_insert_element (EMAILNAME, END);
593146515Sru            }
594146515Sru          xml_insert_element (EMAIL, END);
595146515Sru        }
596146515Sru      else if (html)
597146515Sru        {
598146515Sru          add_html_elt ("<a href=");
599146515Sru          /* don't collapse `--' etc. in the address */
600146515Sru          in_fixed_width_font++;
601146515Sru          execute_string ("\"mailto:%s\"", addr);
602146515Sru          in_fixed_width_font--;
603146515Sru          add_word (">");
604146515Sru          execute_string ("%s", *name ? name : addr);
605146515Sru          add_word ("</a>");
606146515Sru        }
607146515Sru      else
608146515Sru        {
609146515Sru          execute_string ("%s%s", name, *name ? " "  : "");
610146515Sru          in_fixed_width_font++;
611146515Sru          execute_string ("<%s>", addr);
612146515Sru          in_fixed_width_font--;
613146515Sru        }
614146515Sru
615146515Sru      if (addr)
616146515Sru        free (addr);
617146515Sru      if (name)
618146515Sru        free (name);
619146515Sru    }
620146515Sru}
621