Home | History | Annotate | Line # | Download | only in makeinfo
      1  1.4     oster /*	$NetBSD: xref.c,v 1.4 2025/12/31 22:18:50 oster Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* xref.c -- cross references for Texinfo.
      4  1.1  christos    Id: xref.c,v 1.4 2004/12/21 17:28:35 karl Exp
      5  1.1  christos 
      6  1.1  christos    Copyright (C) 2004 Free Software Foundation, Inc.
      7  1.1  christos 
      8  1.1  christos    This program is free software; you can redistribute it and/or modify
      9  1.1  christos    it under the terms of the GNU General Public License as published by
     10  1.1  christos    the Free Software Foundation; either version 2, or (at your option)
     11  1.1  christos    any later version.
     12  1.1  christos 
     13  1.1  christos    This program is distributed in the hope that it will be useful,
     14  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  1.1  christos    GNU General Public License for more details.
     17  1.1  christos 
     18  1.1  christos    You should have received a copy of the GNU General Public License
     19  1.1  christos    along with this program; if not, write to the Free Software Foundation,
     20  1.1  christos    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
     21  1.1  christos 
     22  1.1  christos #include "system.h"
     23  1.1  christos #include "cmds.h"
     24  1.1  christos #include "float.h"
     25  1.1  christos #include "html.h"
     26  1.1  christos #include "index.h"
     27  1.1  christos #include "macro.h"
     28  1.1  christos #include "makeinfo.h"
     29  1.1  christos #include "node.h"
     30  1.1  christos #include "xml.h"
     31  1.1  christos #include "xref.h"
     32  1.1  christos 
     33  1.1  christos /* Flags which control initial output string for xrefs. */
     34  1.1  christos int px_ref_flag = 0;
     35  1.1  christos int ref_flag = 0;
     36  1.1  christos 
     37  1.1  christos /* Called in the multiple-argument case to make sure we generate a valid
     38  1.1  christos    Info reference.  In the single-argument case, the :: we output
     39  1.1  christos    suffices for the Info readers to find the end of the reference.  */
     40  1.1  christos static void
     41  1.1  christos add_xref_punctuation (void)
     42  1.1  christos {
     43  1.1  christos   if (px_ref_flag || ref_flag)  /* user inserts punct after @xref */
     44  1.1  christos     {
     45  1.1  christos       /* Check if there's already punctuation.  */
     46  1.1  christos       int next_char = next_nonwhitespace_character ();
     47  1.1  christos 
     48  1.1  christos       if (next_char == -1)
     49  1.1  christos         /* EOF while looking for punctuation, let's
     50  1.1  christos            insert a period instead of crying.  */
     51  1.1  christos         add_char ('.');
     52  1.1  christos       else if (next_char != ',' && next_char != '.')
     53  1.1  christos         /* period and comma terminate xrefs, and nothing else.  Instead
     54  1.1  christos            of generating an Info reference that can't be followed,
     55  1.1  christos            though, just insert a period.  Not pretty, but functional.  */
     56  1.1  christos         add_char ('.');
     57  1.1  christos     }
     58  1.1  christos }
     59  1.1  christos 
     60  1.1  christos /* Return next comma-delimited argument, but do not cross a close-brace
     61  1.1  christos    boundary.  Clean up whitespace, too.  If EXPAND is nonzero, replace
     62  1.1  christos    the entire brace-delimited argument list with its expansion before
     63  1.1  christos    looking for the next comma.  */
     64  1.1  christos char *
     65  1.1  christos get_xref_token (int expand)
     66  1.1  christos {
     67  1.1  christos   char *string = 0;
     68  1.1  christos 
     69  1.1  christos   if (docbook)
     70  1.1  christos     xml_in_xref_token = 1;
     71  1.1  christos 
     72  1.1  christos   if (expand)
     73  1.1  christos     {
     74  1.1  christos       int old_offset = input_text_offset;
     75  1.1  christos       int old_lineno = line_number;
     76  1.1  christos 
     77  1.1  christos       get_until_in_braces ("}", &string);
     78  1.1  christos       if (curchar () == '}')    /* as opposed to end of text */
     79  1.1  christos         input_text_offset++;
     80  1.1  christos       if (input_text_offset > old_offset)
     81  1.1  christos         {
     82  1.1  christos           int limit = input_text_offset;
     83  1.1  christos 
     84  1.1  christos           input_text_offset = old_offset;
     85  1.1  christos           line_number = old_lineno;
     86  1.1  christos           only_macro_expansion++;
     87  1.1  christos           replace_with_expansion (input_text_offset, &limit);
     88  1.1  christos           only_macro_expansion--;
     89  1.1  christos         }
     90  1.1  christos       free (string);
     91  1.1  christos     }
     92  1.1  christos 
     93  1.1  christos   get_until_in_braces (",", &string);
     94  1.1  christos   if (curchar () == ',')
     95  1.1  christos     input_text_offset++;
     96  1.1  christos   fix_whitespace (string);
     97  1.1  christos 
     98  1.1  christos   if (docbook)
     99  1.1  christos     xml_in_xref_token = 0;
    100  1.1  christos 
    101  1.1  christos   return string;
    102  1.1  christos }
    103  1.1  christos 
    104  1.1  christos 
    105  1.1  christos /* NOTE: If you wonder why the HTML output is produced with such a
    106  1.1  christos    peculiar mix of calls to add_word and execute_string, here's the
    107  1.1  christos    reason.  get_xref_token (1) expands all macros in a reference, but
    108  1.1  christos    any other commands, like @value, @@, etc., are left intact.  To
    109  1.1  christos    expand them, we need to run the arguments through execute_string.
    110  1.1  christos    However, characters like <, &, > and others cannot be let into
    111  1.1  christos    execute_string, because they will be escaped.  See the mess?  */
    112  1.1  christos 
    113  1.1  christos /* Make a cross reference. */
    114  1.1  christos void
    115  1.4     oster cm_xref (int arg, int arg2, int arg3)
    116  1.1  christos {
    117  1.1  christos   if (arg == START)
    118  1.1  christos     {
    119  1.1  christos       char *arg1 = get_xref_token (1); /* expands all macros in xref */
    120  1.1  christos       char *arg2 = get_xref_token (0);
    121  1.1  christos       char *arg3 = get_xref_token (0);
    122  1.1  christos       char *arg4 = get_xref_token (0);
    123  1.1  christos       char *arg5 = get_xref_token (0);
    124  1.1  christos       char *tem;
    125  1.1  christos 
    126  1.1  christos       /* "@xref{,Foo,, Bar, Baz} is not valid usage of @xref.  The
    127  1.1  christos          first argument must never be blank." --rms.
    128  1.1  christos          We hereby comply by disallowing such constructs.  */
    129  1.1  christos       if (!*arg1)
    130  1.1  christos         line_error (_("First argument to cross-reference may not be empty"));
    131  1.1  christos 
    132  1.1  christos       if (docbook)
    133  1.1  christos         {
    134  1.1  christos           if (!ref_flag)
    135  1.1  christos             add_word (px_ref_flag || printing_index
    136  1.1  christos                 ? (char *) _("see ") : (char *) _("See "));
    137  1.1  christos 
    138  1.1  christos           if (!*arg4 && !*arg5)
    139  1.1  christos             {
    140  1.1  christos               char *arg1_id = xml_id (arg1);
    141  1.1  christos 
    142  1.1  christos               if (*arg2 || *arg3)
    143  1.1  christos                 {
    144  1.1  christos                   xml_insert_element_with_attribute (XREFNODENAME, START,
    145  1.1  christos                                                      "linkend=\"%s\"", arg1_id);
    146  1.1  christos                   free (arg1_id);
    147  1.1  christos                   execute_string ("%s", *arg3 ? arg3 : arg2);
    148  1.1  christos                   xml_insert_element (XREFNODENAME, END);
    149  1.1  christos                 }
    150  1.1  christos               else
    151  1.1  christos                 {
    152  1.1  christos                   xml_insert_element_with_attribute (XREF, START,
    153  1.1  christos                                                      "linkend=\"%s\"", arg1_id);
    154  1.1  christos                   xml_insert_element (XREF, END);
    155  1.1  christos                   free (arg1_id);
    156  1.1  christos                 }
    157  1.1  christos             }
    158  1.1  christos           else if (*arg5)
    159  1.1  christos             {
    160  1.1  christos               add_word_args (_("See section ``%s'' in "), *arg3 ? arg3 : arg1);
    161  1.1  christos               xml_insert_element (CITE, START);
    162  1.1  christos               add_word (arg5);
    163  1.1  christos               xml_insert_element (CITE, END);
    164  1.1  christos             }
    165  1.1  christos           else if (*arg4)
    166  1.1  christos             {
    167  1.1  christos               /* Very sad, we are losing xrefs made to ``info only'' books.  */
    168  1.1  christos             }
    169  1.1  christos         }
    170  1.1  christos       else if (xml)
    171  1.1  christos         {
    172  1.1  christos           if (!ref_flag)
    173  1.1  christos             add_word_args ("%s", px_ref_flag ? _("see ") : _("See "));
    174  1.1  christos 
    175  1.1  christos           xml_insert_element (XREF, START);
    176  1.1  christos           xml_insert_element (XREFNODENAME, START);
    177  1.1  christos           execute_string ("%s", arg1);
    178  1.1  christos           xml_insert_element (XREFNODENAME, END);
    179  1.1  christos           if (*arg2)
    180  1.1  christos             {
    181  1.1  christos               xml_insert_element (XREFINFONAME, START);
    182  1.1  christos               execute_string ("%s", arg2);
    183  1.1  christos               xml_insert_element (XREFINFONAME, END);
    184  1.1  christos             }
    185  1.1  christos           if (*arg3)
    186  1.1  christos             {
    187  1.1  christos               xml_insert_element (XREFPRINTEDDESC, START);
    188  1.1  christos               execute_string ("%s", arg3);
    189  1.1  christos               xml_insert_element (XREFPRINTEDDESC, END);
    190  1.1  christos             }
    191  1.1  christos           if (*arg4)
    192  1.1  christos             {
    193  1.1  christos               xml_insert_element (XREFINFOFILE, START);
    194  1.1  christos               execute_string ("%s", arg4);
    195  1.1  christos               xml_insert_element (XREFINFOFILE, END);
    196  1.1  christos             }
    197  1.1  christos           if (*arg5)
    198  1.1  christos             {
    199  1.1  christos               xml_insert_element (XREFPRINTEDNAME, START);
    200  1.1  christos               execute_string ("%s", arg5);
    201  1.1  christos               xml_insert_element (XREFPRINTEDNAME, END);
    202  1.1  christos             }
    203  1.1  christos           xml_insert_element (XREF, END);
    204  1.1  christos         }
    205  1.1  christos       else if (html)
    206  1.1  christos         {
    207  1.1  christos           if (!ref_flag)
    208  1.1  christos             add_word_args ("%s", px_ref_flag ? _("see ") : _("See "));
    209  1.1  christos         }
    210  1.1  christos       else
    211  1.1  christos         add_word_args ("%s", px_ref_flag ? "*note " : "*Note ");
    212  1.1  christos 
    213  1.1  christos       if (!xml)
    214  1.1  christos         {
    215  1.1  christos           if (*arg5 || *arg4)
    216  1.1  christos             {
    217  1.1  christos               /* arg1 - node name
    218  1.1  christos                  arg2 - reference name
    219  1.1  christos                  arg3 - title or topic (and reference name if arg2 is NULL)
    220  1.1  christos                  arg4 - info file name
    221  1.1  christos                  arg5 - printed manual title  */
    222  1.1  christos               char *ref_name;
    223  1.1  christos 
    224  1.1  christos               if (!*arg2)
    225  1.1  christos                 {
    226  1.1  christos                   if (*arg3)
    227  1.1  christos                     ref_name = arg3;
    228  1.1  christos                   else
    229  1.1  christos                     ref_name = arg1;
    230  1.1  christos                 }
    231  1.1  christos               else
    232  1.1  christos                 ref_name = arg2;
    233  1.1  christos 
    234  1.1  christos               if (html)
    235  1.1  christos                 { /* More to do eventually, down to Unicode
    236  1.1  christos                      Normalization Form C.  See the HTML Xref nodes in
    237  1.1  christos                      the manual.  */
    238  1.1  christos                   char *file_arg = arg4;
    239  1.1  christos                   add_html_elt ("<a href=");
    240  1.1  christos 
    241  1.1  christos                   {
    242  1.1  christos                     /* If there's a directory part, ignore it.  */
    243  1.1  christos                     char *p = strrchr (file_arg, '/');
    244  1.1  christos                     if (p)
    245  1.1  christos                       file_arg = p + 1;
    246  1.1  christos 
    247  1.1  christos                   /* If there's a dot, make it a NULL terminator, so the
    248  1.1  christos                      extension does not get into the way.  */
    249  1.1  christos                     p = strrchr (file_arg , '.');
    250  1.1  christos                     if (p != NULL)
    251  1.1  christos                       *p = 0;
    252  1.1  christos                   }
    253  1.1  christos 
    254  1.1  christos                   if (! *file_arg)
    255  1.1  christos                 warning (_("Empty file name for HTML cross reference in `%s'"),
    256  1.1  christos                            arg4);
    257  1.1  christos 
    258  1.1  christos                   /* Note that if we are splitting, and the referenced
    259  1.1  christos                      tag is an anchor rather than a node, we will
    260  1.1  christos                      produce a reference to a file whose name is
    261  1.1  christos                      derived from the anchor name.  However, only
    262  1.1  christos                      nodes create files, so we are referencing a
    263  1.1  christos                      non-existent file.  cm_anchor, which see, deals
    264  1.1  christos                      with that problem.  */
    265  1.1  christos                   if (splitting)
    266  1.1  christos                     execute_string ("\"../%s/", file_arg);
    267  1.1  christos                   else
    268  1.1  christos                     execute_string ("\"%s.html", file_arg);
    269  1.1  christos                   /* Do not collapse -- to -, etc., in references.  */
    270  1.1  christos                   in_fixed_width_font++;
    271  1.1  christos                   tem = expansion (arg1, 0); /* expand @-commands in node */
    272  1.1  christos                   in_fixed_width_font--;
    273  1.1  christos                   add_anchor_name (tem, 1);
    274  1.1  christos                   free (tem);
    275  1.1  christos                   add_word ("\">");
    276  1.1  christos                   execute_string ("%s",ref_name);
    277  1.1  christos                   add_word ("</a>");
    278  1.1  christos                 }
    279  1.1  christos               else
    280  1.1  christos                 {
    281  1.1  christos                   execute_string ("%s:", ref_name);
    282  1.1  christos                   in_fixed_width_font++;
    283  1.1  christos                   execute_string (" (%s)%s", arg4, arg1);
    284  1.1  christos                   add_xref_punctuation ();
    285  1.1  christos                   in_fixed_width_font--;
    286  1.1  christos                 }
    287  1.1  christos 
    288  1.1  christos               /* Free all of the arguments found. */
    289  1.1  christos               if (arg1) free (arg1);
    290  1.1  christos               if (arg2) free (arg2);
    291  1.1  christos               if (arg3) free (arg3);
    292  1.1  christos               if (arg4) free (arg4);
    293  1.1  christos               if (arg5) free (arg5);
    294  1.1  christos               return;
    295  1.1  christos             }
    296  1.1  christos           else
    297  1.1  christos             remember_node_reference (arg1, line_number, followed_reference);
    298  1.1  christos 
    299  1.1  christos           if (*arg3)
    300  1.1  christos             {
    301  1.1  christos               if (html)
    302  1.1  christos                 {
    303  1.1  christos                   add_html_elt ("<a href=\"");
    304  1.1  christos                   in_fixed_width_font++;
    305  1.1  christos                   tem = expansion (arg1, 0);
    306  1.1  christos                   in_fixed_width_font--;
    307  1.1  christos                   add_anchor_name (tem, 1);
    308  1.1  christos                   free (tem);
    309  1.1  christos                   add_word ("\">");
    310  1.1  christos                   execute_string ("%s", *arg2 ? arg2 : arg3);
    311  1.1  christos                   add_word ("</a>");
    312  1.1  christos                 }
    313  1.1  christos               else
    314  1.1  christos                 {
    315  1.1  christos                   execute_string ("%s:", *arg2 ? arg2 : arg3);
    316  1.1  christos                   in_fixed_width_font++;
    317  1.1  christos                   execute_string (" %s", arg1);
    318  1.1  christos                   add_xref_punctuation ();
    319  1.1  christos                   in_fixed_width_font--;
    320  1.1  christos                 }
    321  1.1  christos             }
    322  1.1  christos           else
    323  1.1  christos             {
    324  1.1  christos               if (html)
    325  1.1  christos                 {
    326  1.1  christos                   add_html_elt ("<a href=\"");
    327  1.1  christos                   in_fixed_width_font++;
    328  1.1  christos                   tem = expansion (arg1, 0);
    329  1.1  christos                   in_fixed_width_font--;
    330  1.1  christos                   add_anchor_name (tem, 1);
    331  1.1  christos                   free (tem);
    332  1.1  christos                   add_word ("\">");
    333  1.1  christos                   if (*arg2)
    334  1.1  christos                     execute_string ("%s", arg2);
    335  1.1  christos                   else
    336  1.1  christos                     {
    337  1.1  christos                       char *fref = get_float_ref (arg1);
    338  1.1  christos                       execute_string ("%s", fref ? fref : arg1);
    339  1.1  christos                       free (fref);
    340  1.1  christos                     }
    341  1.1  christos                   add_word ("</a>");
    342  1.1  christos                 }
    343  1.1  christos               else
    344  1.1  christos                 {
    345  1.1  christos                   if (*arg2)
    346  1.1  christos                     {
    347  1.1  christos                       execute_string ("%s:", arg2);
    348  1.1  christos                       in_fixed_width_font++;
    349  1.1  christos                       execute_string (" %s", arg1);
    350  1.1  christos                       add_xref_punctuation ();
    351  1.1  christos                       in_fixed_width_font--;
    352  1.1  christos                     }
    353  1.1  christos                   else
    354  1.1  christos                     {
    355  1.1  christos                       char *fref = get_float_ref (arg1);
    356  1.1  christos                       if (fref)
    357  1.1  christos                         { /* Reference is being made to a float.  */
    358  1.1  christos                           execute_string ("%s:", fref);
    359  1.1  christos                           in_fixed_width_font++;
    360  1.1  christos                           execute_string (" %s", arg1);
    361  1.1  christos                           add_xref_punctuation ();
    362  1.1  christos                           in_fixed_width_font--;
    363  1.1  christos                         }
    364  1.1  christos                       else
    365  1.1  christos                         {
    366  1.1  christos                           in_fixed_width_font++;
    367  1.1  christos                           execute_string ("%s::", arg1);
    368  1.1  christos                           in_fixed_width_font--;
    369  1.1  christos                         }
    370  1.1  christos                     }
    371  1.1  christos                 }
    372  1.1  christos             }
    373  1.1  christos         }
    374  1.1  christos       /* Free all of the arguments found. */
    375  1.1  christos       if (arg1) free (arg1);
    376  1.1  christos       if (arg2) free (arg2);
    377  1.1  christos       if (arg3) free (arg3);
    378  1.1  christos       if (arg4) free (arg4);
    379  1.1  christos       if (arg5) free (arg5);
    380  1.1  christos     }
    381  1.1  christos   else
    382  1.1  christos     { /* Check that the next non-whitespace character is valid to follow
    383  1.1  christos          an xref (so Info readers can find the node names).
    384  1.1  christos          `input_text_offset' is pointing at the "}" which ended the xref
    385  1.1  christos          command.  This is not used for @pxref or @ref, since we insert
    386  1.1  christos          the necessary punctuation above, if needed.  */
    387  1.1  christos       int temp = next_nonwhitespace_character ();
    388  1.1  christos 
    389  1.1  christos       if (temp == -1)
    390  1.1  christos         warning (_("End of file reached while looking for `.' or `,'"));
    391  1.1  christos       else if (temp != '.' && temp != ',')
    392  1.1  christos         warning (_("`.' or `,' must follow @%s, not `%c'"), command, temp);
    393  1.1  christos     }
    394  1.1  christos }
    395  1.1  christos 
    396  1.1  christos void
    397  1.4     oster cm_pxref (int arg, int arg2, int arg3)
    398  1.1  christos {
    399  1.1  christos   if (arg == START)
    400  1.1  christos     {
    401  1.1  christos       px_ref_flag++;
    402  1.4     oster       cm_xref (arg, 0, 0);
    403  1.1  christos       px_ref_flag--;
    404  1.1  christos     }
    405  1.1  christos   /* cm_xref isn't called with arg == END, which disables the code near
    406  1.1  christos      the end of cm_xref that checks for `.' or `,' after the
    407  1.1  christos      cross-reference.  This is because cm_xref generates the required
    408  1.1  christos      character itself (when needed) if px_ref_flag is set.  */
    409  1.1  christos }
    410  1.1  christos 
    411  1.1  christos void
    412  1.4     oster cm_ref (int arg, int arg2, int arg3)
    413  1.1  christos {
    414  1.1  christos   /* See the comments in cm_pxref about the checks for punctuation.  */
    415  1.1  christos   if (arg == START)
    416  1.1  christos     {
    417  1.1  christos       ref_flag++;
    418  1.4     oster       cm_xref (arg, 0, 0);
    419  1.1  christos       ref_flag--;
    420  1.1  christos     }
    421  1.1  christos }
    422  1.1  christos 
    423  1.1  christos void
    424  1.4     oster cm_inforef (int arg, int arg2, int arg3)
    425  1.1  christos {
    426  1.1  christos   if (arg == START)
    427  1.1  christos     {
    428  1.1  christos       char *node = get_xref_token (1); /* expands all macros in inforef */
    429  1.1  christos       char *pname = get_xref_token (0);
    430  1.1  christos       char *file = get_xref_token (0);
    431  1.1  christos 
    432  1.1  christos       /* (see comments at cm_xref).  */
    433  1.1  christos       if (!*node)
    434  1.1  christos         line_error (_("First argument to @inforef may not be empty"));
    435  1.1  christos 
    436  1.1  christos       if (xml && !docbook)
    437  1.1  christos         {
    438  1.1  christos           xml_insert_element (INFOREF, START);
    439  1.1  christos           xml_insert_element (INFOREFNODENAME, START);
    440  1.1  christos           execute_string ("%s", node);
    441  1.1  christos           xml_insert_element (INFOREFNODENAME, END);
    442  1.1  christos           if (*pname)
    443  1.1  christos             {
    444  1.1  christos               xml_insert_element (INFOREFREFNAME, START);
    445  1.1  christos               execute_string ("%s", pname);
    446  1.1  christos               xml_insert_element (INFOREFREFNAME, END);
    447  1.1  christos             }
    448  1.1  christos           xml_insert_element (INFOREFINFONAME, START);
    449  1.1  christos           execute_string ("%s", file);
    450  1.1  christos           xml_insert_element (INFOREFINFONAME, END);
    451  1.1  christos 
    452  1.1  christos           xml_insert_element (INFOREF, END);
    453  1.1  christos         }
    454  1.1  christos       else if (html)
    455  1.1  christos         {
    456  1.1  christos           char *tem;
    457  1.1  christos 
    458  1.1  christos           add_word ((char *) _("see "));
    459  1.1  christos           /* html fixxme: revisit this */
    460  1.1  christos           add_html_elt ("<a href=");
    461  1.1  christos           if (splitting)
    462  1.1  christos             execute_string ("\"../%s/", file);
    463  1.1  christos           else
    464  1.1  christos             execute_string ("\"%s.html", file);
    465  1.1  christos           tem = expansion (node, 0);
    466  1.1  christos           add_anchor_name (tem, 1);
    467  1.1  christos           add_word ("\">");
    468  1.1  christos           execute_string ("%s", *pname ? pname : tem);
    469  1.1  christos           add_word ("</a>");
    470  1.1  christos           free (tem);
    471  1.1  christos         }
    472  1.1  christos       else
    473  1.1  christos         {
    474  1.1  christos           if (*pname)
    475  1.1  christos             execute_string ("*note %s: (%s)%s", pname, file, node);
    476  1.1  christos           else
    477  1.1  christos             execute_string ("*note (%s)%s::", file, node);
    478  1.1  christos         }
    479  1.1  christos 
    480  1.1  christos       free (node);
    481  1.1  christos       free (pname);
    482  1.1  christos       free (file);
    483  1.1  christos     }
    484  1.1  christos }
    485  1.1  christos 
    486  1.1  christos /* A URL reference.  */
    487  1.1  christos void
    488  1.4     oster cm_uref (int arg, int arg2, int arg3)
    489  1.1  christos {
    490  1.1  christos   if (arg == START)
    491  1.1  christos     {
    492  1.1  christos       extern int printing_index;
    493  1.1  christos       char *url  = get_xref_token (1); /* expands all macros in uref */
    494  1.1  christos       char *desc = get_xref_token (0);
    495  1.1  christos       char *replacement = get_xref_token (0);
    496  1.1  christos 
    497  1.1  christos       if (docbook)
    498  1.1  christos         {
    499  1.1  christos           xml_insert_element_with_attribute (UREF, START, "url=\"%s\"",
    500  1.1  christos               text_expansion (url));
    501  1.1  christos           if (*replacement)
    502  1.1  christos             execute_string ("%s", replacement);
    503  1.1  christos           else if (*desc)
    504  1.1  christos             execute_string ("%s", desc);
    505  1.1  christos           else
    506  1.1  christos             execute_string ("%s", url);
    507  1.1  christos           xml_insert_element (UREF, END);
    508  1.1  christos         }
    509  1.1  christos       else if (xml)
    510  1.1  christos         {
    511  1.1  christos           xml_insert_element (UREF, START);
    512  1.1  christos           xml_insert_element (UREFURL, START);
    513  1.1  christos           execute_string ("%s", url);
    514  1.1  christos           xml_insert_element (UREFURL, END);
    515  1.1  christos           if (*desc)
    516  1.1  christos             {
    517  1.1  christos               xml_insert_element (UREFDESC, START);
    518  1.1  christos               execute_string ("%s", desc);
    519  1.1  christos               xml_insert_element (UREFDESC, END);
    520  1.1  christos             }
    521  1.1  christos           if (*replacement)
    522  1.1  christos             {
    523  1.1  christos               xml_insert_element (UREFREPLACEMENT, START);
    524  1.1  christos               execute_string ("%s", replacement);
    525  1.1  christos               xml_insert_element (UREFREPLACEMENT, END);
    526  1.1  christos             }
    527  1.1  christos           xml_insert_element (UREF, END);
    528  1.1  christos         }
    529  1.1  christos       else if (html)
    530  1.1  christos         { /* never need to show the url */
    531  1.1  christos           add_html_elt ("<a href=");
    532  1.1  christos           /* don't collapse `--' etc. in the url */
    533  1.1  christos           in_fixed_width_font++;
    534  1.1  christos           execute_string ("\"%s\"", url);
    535  1.1  christos           in_fixed_width_font--;
    536  1.1  christos           add_word (">");
    537  1.1  christos           execute_string ("%s", *replacement ? replacement
    538  1.1  christos                                 : (*desc ? desc : url));
    539  1.1  christos           add_word ("</a>");
    540  1.1  christos         }
    541  1.1  christos       else if (*replacement) /* do not show the url */
    542  1.1  christos         execute_string ("%s", replacement);
    543  1.1  christos       else if (*desc)        /* show both text and url */
    544  1.1  christos         {
    545  1.1  christos           execute_string ("%s ", desc);
    546  1.1  christos           in_fixed_width_font++;
    547  1.1  christos           execute_string ("(%s)", url);
    548  1.1  christos           in_fixed_width_font--;
    549  1.1  christos         }
    550  1.1  christos       else /* no text at all, so have the url to show */
    551  1.1  christos         {
    552  1.1  christos           in_fixed_width_font++;
    553  1.1  christos           execute_string ("%s%s%s",
    554  1.1  christos                           printing_index ? "" : "`",
    555  1.1  christos                           url,
    556  1.1  christos                           printing_index ? "" : "'");
    557  1.1  christos           in_fixed_width_font--;
    558  1.1  christos         }
    559  1.1  christos       if (url)
    560  1.1  christos         free (url);
    561  1.1  christos       if (desc)
    562  1.1  christos         free (desc);
    563  1.1  christos       if (replacement)
    564  1.1  christos         free (replacement);
    565  1.1  christos     }
    566  1.1  christos }
    567  1.1  christos 
    568  1.1  christos /* An email reference.  */
    569  1.1  christos void
    570  1.4     oster cm_email (int arg, int arg2, int arg3)
    571  1.1  christos {
    572  1.1  christos   if (arg == START)
    573  1.1  christos     {
    574  1.1  christos       char *addr = get_xref_token (1); /* expands all macros in email */
    575  1.1  christos       char *name = get_xref_token (0);
    576  1.1  christos 
    577  1.1  christos       if (xml && docbook)
    578  1.1  christos         {
    579  1.1  christos           xml_insert_element_with_attribute (EMAIL, START, "url=\"mailto:%s\"", addr);
    580  1.1  christos           if (*name)
    581  1.1  christos               execute_string ("%s", name);
    582  1.1  christos           xml_insert_element (EMAIL, END);
    583  1.1  christos         }
    584  1.1  christos       else if (xml)
    585  1.1  christos         {
    586  1.1  christos           xml_insert_element (EMAIL, START);
    587  1.1  christos           xml_insert_element (EMAILADDRESS, START);
    588  1.1  christos           execute_string ("%s", addr);
    589  1.1  christos           xml_insert_element (EMAILADDRESS, END);
    590  1.1  christos           if (*name)
    591  1.1  christos             {
    592  1.1  christos               xml_insert_element (EMAILNAME, START);
    593  1.1  christos               execute_string ("%s", name);
    594  1.1  christos               xml_insert_element (EMAILNAME, END);
    595  1.1  christos             }
    596  1.1  christos           xml_insert_element (EMAIL, END);
    597  1.1  christos         }
    598  1.1  christos       else if (html)
    599  1.1  christos         {
    600  1.1  christos           add_html_elt ("<a href=");
    601  1.1  christos           /* don't collapse `--' etc. in the address */
    602  1.1  christos           in_fixed_width_font++;
    603  1.1  christos           execute_string ("\"mailto:%s\"", addr);
    604  1.1  christos           in_fixed_width_font--;
    605  1.1  christos           add_word (">");
    606  1.1  christos           execute_string ("%s", *name ? name : addr);
    607  1.1  christos           add_word ("</a>");
    608  1.1  christos         }
    609  1.1  christos       else
    610  1.1  christos         {
    611  1.1  christos           execute_string ("%s%s", name, *name ? " "  : "");
    612  1.1  christos           in_fixed_width_font++;
    613  1.1  christos           execute_string ("<%s>", addr);
    614  1.1  christos           in_fixed_width_font--;
    615  1.1  christos         }
    616  1.1  christos 
    617  1.1  christos       if (addr)
    618  1.1  christos         free (addr);
    619  1.1  christos       if (name)
    620  1.1  christos         free (name);
    621  1.1  christos     }
    622  1.1  christos }
    623