123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633 |
- /* xref.c -- cross references for Texinfo.
- $Id: xref.c,v 1.14 2007-09-26 20:53:40 karl Exp $
- Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "system.h"
- #include "cmds.h"
- #include "float.h"
- #include "html.h"
- #include "index.h"
- #include "macro.h"
- #include "makeinfo.h"
- #include "node.h"
- #include "xml.h"
- #include "xref.h"
- /* Flags which control initial output string for xrefs. */
- int px_ref_flag = 0;
- int ref_flag = 0;
- /* Called in the multiple-argument case to make sure we generate a valid
- Info reference. In the single-argument case, the :: we output
- suffices for the Info readers to find the end of the reference. */
- static void
- add_xref_punctuation (void)
- {
- if (px_ref_flag || ref_flag) /* user inserts punct after @xref */
- {
- /* Check if there's already punctuation. */
- int next_char = next_nonwhitespace_character ();
- if (next_char == -1)
- /* EOF while looking for punctuation, let's
- insert a period instead of crying. */
- add_char ('.');
- else if (next_char != ',' && next_char != '.')
- /* period and comma terminate xrefs, and nothing else. Instead
- of generating an Info reference that can't be followed,
- though, just insert a period. Not pretty, but functional. */
- add_char ('.');
- }
- }
- /* Return next comma-delimited argument, but do not cross a close-brace
- boundary. Clean up whitespace, too. If EXPAND is nonzero, replace
- the entire brace-delimited argument list with its expansion before
- looking for the next comma. */
- char *
- get_xref_token (int expand)
- {
- char *string = 0;
- if (docbook)
- xml_in_xref_token = 1;
- if (expand)
- {
- int old_offset = input_text_offset;
- int old_lineno = line_number;
- get_until_in_braces ("}", &string);
- if (curchar () == '}') /* as opposed to end of text */
- input_text_offset++;
- if (input_text_offset > old_offset)
- {
- int limit = input_text_offset;
- input_text_offset = old_offset;
- line_number = old_lineno;
- only_macro_expansion++;
- replace_with_expansion (input_text_offset, &limit);
- only_macro_expansion--;
- }
- free (string);
- }
- get_until_in_braces (",", &string);
- if (curchar () == ',')
- input_text_offset++;
- fix_whitespace (string);
- if (docbook)
- xml_in_xref_token = 0;
- return string;
- }
- /* NOTE: If you wonder why the HTML output is produced with such a
- peculiar mix of calls to add_word and execute_string, here's the
- reason. get_xref_token (1) expands all macros in a reference, but
- any other commands, like @value, @@, etc., are left intact. To
- expand them, we need to run the arguments through execute_string.
- However, characters like <, &, > and others cannot be let into
- execute_string, because they will be escaped. See the mess? */
- /* Make a cross reference. */
- void
- cm_xref (int arg)
- {
- if (arg == START)
- {
- char *arg1 = get_xref_token (1); /* expands all macros in xref */
- char *arg2 = get_xref_token (0);
- char *arg3 = get_xref_token (0);
- char *arg4 = get_xref_token (0);
- char *arg5 = get_xref_token (0);
- char *tem;
- /* "@xref{,Foo,, Bar, Baz} is not valid usage of @xref. The
- first argument must never be blank." --rms.
- We hereby comply by disallowing such constructs. */
- if (!*arg1)
- line_error (_("First argument to cross-reference may not be empty"));
- if (docbook)
- {
- if (!ref_flag)
- add_word (px_ref_flag || printing_index
- ? (char *) gdt("see ") : (char *) gdt("See "));
- if (!*arg4 && !*arg5)
- {
- char *arg1_id = xml_id (arg1);
- if (*arg2 || *arg3)
- {
- xml_insert_element_with_attribute (XREFNODENAME, START,
- "linkend=\"%s\"", arg1_id);
- free (arg1_id);
- execute_string ("%s", *arg3 ? arg3 : arg2);
- xml_insert_element (XREFNODENAME, END);
- }
- else
- {
- xml_insert_element_with_attribute (XREF, START,
- "linkend=\"%s\"", arg1_id);
- xml_insert_element (XREF, END);
- free (arg1_id);
- }
- }
- else if (*arg5)
- {
- add_word_args (gdt("See section ``%s'' in "), *arg3 ? arg3 : arg1);
- xml_insert_element (CITE, START);
- add_word (arg5);
- xml_insert_element (CITE, END);
- }
- else if (*arg4)
- {
- /* Very sad, we are losing xrefs made to ``info only'' books. */
- }
- }
- else if (xml)
- {
- if (!ref_flag)
- add_word_args ("%s", px_ref_flag ? gdt("see ") : gdt("See "));
- xml_insert_element (XREF, START);
- xml_insert_element (XREFNODENAME, START);
- execute_string ("%s", arg1);
- xml_insert_element (XREFNODENAME, END);
- if (*arg2)
- {
- xml_insert_element (XREFINFONAME, START);
- execute_string ("%s", arg2);
- xml_insert_element (XREFINFONAME, END);
- }
- if (*arg3)
- {
- xml_insert_element (XREFPRINTEDDESC, START);
- execute_string ("%s", arg3);
- xml_insert_element (XREFPRINTEDDESC, END);
- }
- if (*arg4)
- {
- xml_insert_element (XREFINFOFILE, START);
- execute_string ("%s", arg4);
- xml_insert_element (XREFINFOFILE, END);
- }
- if (*arg5)
- {
- xml_insert_element (XREFPRINTEDNAME, START);
- execute_string ("%s", arg5);
- xml_insert_element (XREFPRINTEDNAME, END);
- }
- xml_insert_element (XREF, END);
- }
- else if (html)
- {
- if (!ref_flag)
- add_word_args ("%s", px_ref_flag ? gdt("see ") : gdt("See "));
- }
- else
- add_word_args ("%s", px_ref_flag || ref_flag ? "*note " : "*Note ");
- if (!xml)
- {
- if (*arg5 || *arg4)
- {
- /* arg1 - node name
- arg2 - reference name
- arg3 - title or topic (and reference name if arg2 is NULL)
- arg4 - info file name
- arg5 - printed manual title */
- char *ref_name;
- if (!*arg2)
- {
- if (*arg3)
- ref_name = arg3;
- else
- ref_name = arg1;
- }
- else
- ref_name = arg2;
- if (html)
- { /* More to do eventually, down to Unicode
- Normalization Form C. See the HTML Xref nodes in
- the manual. */
- char *file_arg = arg4;
- add_html_elt ("<a href=");
- {
- /* If there's a directory part, ignore it. */
- char *p = strrchr (file_arg, '/');
- if (p)
- file_arg = p + 1;
- /* If there's a dot, make it a NULL terminator, so the
- extension does not get into the way. */
- p = strrchr (file_arg , '.');
- if (p != NULL)
- *p = 0;
- }
-
- if (! *file_arg)
- warning (_("Empty file name for HTML cross reference in `%s'"),
- arg4);
- /* Note that if we are splitting, and the referenced
- tag is an anchor rather than a node, we will
- produce a reference to a file whose name is
- derived from the anchor name. However, only
- nodes create files, so we are referencing a
- non-existent file. cm_anchor, which see, deals
- with that problem. */
- if (splitting)
- execute_string ("\"../%s/", file_arg);
- else
- execute_string ("\"%s.html", file_arg);
- /* Do not collapse -- to -, etc., in references. */
- in_fixed_width_font++;
- tem = expansion (arg1, 0); /* expand @-commands in node */
- in_fixed_width_font--;
- add_anchor_name (tem, 1);
- free (tem);
- add_word ("\">");
- execute_string ("%s",ref_name);
- add_word ("</a>");
- }
- else
- {
- execute_string ("%s:", ref_name);
- in_fixed_width_font++;
- execute_string (" (%s)%s", arg4, arg1);
- add_xref_punctuation ();
- in_fixed_width_font--;
- }
- /* Free all of the arguments found. */
- if (arg1) free (arg1);
- if (arg2) free (arg2);
- if (arg3) free (arg3);
- if (arg4) free (arg4);
- if (arg5) free (arg5);
- return;
- }
- else
- remember_node_reference (arg1, line_number, followed_reference);
- if (*arg3)
- {
- if (html)
- {
- add_html_elt ("<a href=\"");
- in_fixed_width_font++;
- tem = expansion (arg1, 0);
- in_fixed_width_font--;
- add_anchor_name (tem, 1);
- free (tem);
- add_word ("\">");
- execute_string ("%s", *arg2 ? arg2 : arg3);
- add_word ("</a>");
- }
- else
- {
- execute_string ("%s:", *arg2 ? arg2 : arg3);
- in_fixed_width_font++;
- execute_string (" %s", arg1);
- add_xref_punctuation ();
- in_fixed_width_font--;
- }
- }
- else
- {
- if (html)
- {
- add_html_elt ("<a href=\"");
- in_fixed_width_font++;
- tem = expansion (arg1, 0);
- in_fixed_width_font--;
- add_anchor_name (tem, 1);
- free (tem);
- add_word ("\">");
- if (*arg2)
- execute_string ("%s", arg2);
- else
- {
- char *fref = get_float_ref (arg1);
- execute_string ("%s", fref ? fref : arg1);
- free (fref);
- }
- add_word ("</a>");
- }
- else
- {
- if (*arg2)
- {
- execute_string ("%s:", arg2);
- in_fixed_width_font++;
- execute_string (" %s", arg1);
- add_xref_punctuation ();
- in_fixed_width_font--;
- }
- else
- {
- char *fref = get_float_ref (arg1);
- if (fref)
- { /* Reference is being made to a float. */
- execute_string ("%s:", fref);
- in_fixed_width_font++;
- execute_string (" %s", arg1);
- add_xref_punctuation ();
- in_fixed_width_font--;
- }
- else
- {
- in_fixed_width_font++;
- execute_string ("%s::", arg1);
- in_fixed_width_font--;
- }
- }
- }
- }
- }
- /* Free all of the arguments found. */
- if (arg1) free (arg1);
- if (arg2) free (arg2);
- if (arg3) free (arg3);
- if (arg4) free (arg4);
- if (arg5) free (arg5);
- }
- else
- { /* Check that the next non-whitespace character is valid to follow
- an xref (so Info readers can find the node names).
- `input_text_offset' is pointing at the "}" which ended the xref
- command. This is not used for @pxref or @ref, since we insert
- the necessary punctuation above, if needed. */
- int temp = next_nonwhitespace_character ();
- if (temp == -1)
- warning (_("End of file reached while looking for `.' or `,'"));
- else if (temp != '.' && temp != ',')
- {
- warning (_("`.' or `,' must follow @%s, not `%c'"), command, temp);
- if (temp == ')')
- warning (_("for cross-references in parentheses, use @pxref"));
- }
- }
- }
- void
- cm_pxref (int arg)
- {
- if (arg == START)
- {
- px_ref_flag++;
- cm_xref (arg);
- px_ref_flag--;
- }
- /* cm_xref isn't called with arg == END, which disables the code near
- the end of cm_xref that checks for `.' or `,' after the
- cross-reference. This is because cm_xref generates the required
- character itself (when needed) if px_ref_flag is set. */
- }
- void
- cm_ref (int arg)
- {
- /* See the comments in cm_pxref about the checks for punctuation. */
- if (arg == START)
- {
- ref_flag++;
- cm_xref (arg);
- ref_flag--;
- }
- }
- void
- cm_inforef (int arg)
- {
- if (arg == START)
- {
- char *node = get_xref_token (1); /* expands all macros in inforef */
- char *pname = get_xref_token (0);
- char *file = get_xref_token (0);
- /* (see comments at cm_xref). */
- if (!*node)
- line_error (_("First argument to @inforef may not be empty"));
- if (xml && !docbook)
- {
- xml_insert_element (INFOREF, START);
- xml_insert_element (INFOREFNODENAME, START);
- execute_string ("%s", node);
- xml_insert_element (INFOREFNODENAME, END);
- if (*pname)
- {
- xml_insert_element (INFOREFREFNAME, START);
- execute_string ("%s", pname);
- xml_insert_element (INFOREFREFNAME, END);
- }
- xml_insert_element (INFOREFINFONAME, START);
- execute_string ("%s", file);
- xml_insert_element (INFOREFINFONAME, END);
- xml_insert_element (INFOREF, END);
- }
- else if (html)
- {
- char *tem;
- add_word ((char *) gdt("see "));
- /* html fixxme: revisit this */
- add_html_elt ("<a href=");
- if (splitting)
- execute_string ("\"../%s/", file);
- else
- execute_string ("\"%s.html", file);
- tem = expansion (node, 0);
- add_anchor_name (tem, 1);
- add_word ("\">");
- execute_string ("%s", *pname ? pname : tem);
- add_word ("</a>");
- free (tem);
- }
- else
- {
- if (*pname)
- execute_string ("*note %s: (%s)%s", pname, file, node);
- else
- execute_string ("*note (%s)%s::", file, node);
- }
- free (node);
- free (pname);
- free (file);
- }
- }
- /* A URL reference. */
- void
- cm_uref (int arg)
- {
- if (arg == START)
- {
- char *url = get_xref_token (1); /* expands all macros in uref */
- char *desc = get_xref_token (0);
- char *replacement = get_xref_token (0);
- if (docbook)
- {
- xml_insert_element_with_attribute (UREF, START, "url=\"%s\"",
- maybe_escaped_expansion (url, 0, 1));
- if (*replacement)
- execute_string ("%s", replacement);
- else if (*desc)
- execute_string ("%s", desc);
- else
- execute_string ("%s", url);
- xml_insert_element (UREF, END);
- }
- else if (xml)
- {
- xml_insert_element (UREF, START);
- xml_insert_element (UREFURL, START);
- execute_string ("%s", url);
- xml_insert_element (UREFURL, END);
- if (*desc)
- {
- xml_insert_element (UREFDESC, START);
- execute_string ("%s", desc);
- xml_insert_element (UREFDESC, END);
- }
- if (*replacement)
- {
- xml_insert_element (UREFREPLACEMENT, START);
- execute_string ("%s", replacement);
- xml_insert_element (UREFREPLACEMENT, END);
- }
- xml_insert_element (UREF, END);
- }
- else if (html)
- { /* never need to show the url */
- add_html_elt ("<a href=");
- /* don't collapse `--' etc. in the url */
- in_fixed_width_font++;
- execute_string ("\"%s\"", url);
- in_fixed_width_font--;
- add_word (">");
- execute_string ("%s", *replacement ? replacement
- : (*desc ? desc : url));
- add_word ("</a>");
- }
- else if (*replacement) /* do not show the url */
- execute_string ("%s", replacement);
- else if (*desc) /* show both text and url */
- {
- execute_string ("%s ", desc);
- in_fixed_width_font++;
- execute_string ("(%s)", url);
- in_fixed_width_font--;
- }
- else /* no text at all, so have the url to show */
- {
- in_fixed_width_font++;
- execute_string ("%s%s%s",
- printing_index ? "" : "`",
- url,
- printing_index ? "" : "'");
- in_fixed_width_font--;
- }
- if (url)
- free (url);
- if (desc)
- free (desc);
- if (replacement)
- free (replacement);
- }
- }
- /* An email reference. */
- void
- cm_email (int arg)
- {
- if (arg == START)
- {
- char *addr = get_xref_token (1); /* expands all macros in email */
- char *name = get_xref_token (0);
- if (xml && docbook)
- {
- if (*name)
- {
- xml_insert_element_with_attribute (EMAIL, START,
- "url=\"mailto:%s\"",
- maybe_escaped_expansion (addr, 0, 1));
- execute_string ("%s", name);
- xml_insert_element (EMAIL, END);
- }
- else
- {
- xml_insert_element (EMAILADDRESS, START);
- execute_string ("%s", addr);
- xml_insert_element (EMAILADDRESS, END);
- }
- }
- else if (xml)
- {
- xml_insert_element (EMAIL, START);
- xml_insert_element (EMAILADDRESS, START);
- execute_string ("%s", addr);
- xml_insert_element (EMAILADDRESS, END);
- if (*name)
- {
- xml_insert_element (EMAILNAME, START);
- execute_string ("%s", name);
- xml_insert_element (EMAILNAME, END);
- }
- xml_insert_element (EMAIL, END);
- }
- else if (html)
- {
- add_html_elt ("<a href=");
- /* don't collapse `--' etc. in the address */
- in_fixed_width_font++;
- execute_string ("\"mailto:%s\"", addr);
- in_fixed_width_font--;
- add_word (">");
- execute_string ("%s", *name ? name : addr);
- add_word ("</a>");
- }
- else
- {
- execute_string ("%s%s", name, *name ? " " : "");
- in_fixed_width_font++;
- execute_string ("<%s>", addr);
- in_fixed_width_font--;
- }
- if (addr)
- free (addr);
- if (name)
- free (name);
- }
- }
|