diff options
Diffstat (limited to 'contrib/texinfo/makeinfo/xref.c')
-rw-r--r-- | contrib/texinfo/makeinfo/xref.c | 620 |
1 files changed, 620 insertions, 0 deletions
diff --git a/contrib/texinfo/makeinfo/xref.c b/contrib/texinfo/makeinfo/xref.c new file mode 100644 index 0000000..314d4a0 --- /dev/null +++ b/contrib/texinfo/makeinfo/xref.c @@ -0,0 +1,620 @@ +/* xref.c -- cross references for Texinfo. + $Id: xref.c,v 1.4 2004/12/21 17:28:35 karl Exp $ + + Copyright (C) 2004 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 2, 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#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 *) _("see ") : (char *) _("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 (_("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 ? _("see ") : _("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 ? _("see ") : _("See ")); + } + else + add_word_args ("%s", px_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); + } +} + +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 *) _("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) + { + extern int printing_index; + 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\"", + text_expansion (url)); + 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) + { + xml_insert_element_with_attribute (EMAIL, START, "url=\"mailto:%s\"", addr); + if (*name) + execute_string ("%s", name); + xml_insert_element (EMAIL, 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); + } +} |