1 /* html.c -- html-related utilities.
2 $Id: html.c,v 1.26 2002/03/23 20:39:49 karl Exp $
4 Copyright (C) 1999, 2000, 01, 02 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 #include "sectioning.h"
28 int html_output_head_p = 0;
33 static char *html_title = NULL;
34 static int html_title_written = 0;
36 if (html_output_head_p)
38 html_output_head_p = 1;
40 /* The <title> should not have markup, so use text_expansion. */
42 html_title = title ? text_expansion (title) : _("Untitled");
44 add_word_args ("<html lang=\"%s\">\n<head>\n<title>%s</title>\n",
45 language_table[language_code].abbrev, html_title);
47 add_word ("<meta http-equiv=\"Content-Type\" content=\"text/html");
48 if (document_encoding_code != no_encoding)
49 add_word_args ("; charset=%s",
50 encoding_table[document_encoding_code].ecname);
53 if (!document_description)
54 document_description = html_title;
56 add_word_args ("<meta name=description content=\"%s\">\n",
57 document_description);
58 add_word_args ("<meta name=generator content=\"makeinfo %s\">\n", VERSION);
59 add_word ("<link href=\"http://www.gnu.org/software/texinfo/\" rel=generator-home>\n");
62 { /* copying_text has already been fully expanded in
63 begin_insertion (by full_expansion), so use insert_ rather than
64 add_. It is not ideal that we include the html markup here within
65 <head>, but the alternative is to have yet more and different
66 expansions of the copying text. Yuck. */
67 insert_string ("<!--\n");
68 insert_string (copying_text);
69 insert_string ("-->\n");
72 add_word ("</head>\n<body>\n");
74 if (title && !html_title_written)
76 add_word_args ("<h1>%s</h1>\n", html_title);
77 html_title_written = 1;
82 /* Escape HTML special characters in the string if necessary,
83 returning a pointer to a possibly newly-allocated one. */
85 escape_string (string)
93 /* Find how much to allocate. */
97 newlen += 5; /* `&' */
101 newlen += 4; /* `<', `>' */
109 if (newlen == i) return string; /* Already OK. */
111 newstring = xmalloc (newlen);
118 strcpy (newstring, "&");
122 strcpy (newstring, "<");
126 strcpy (newstring, ">");
130 newstring[0] = string[i];
136 return newstring - newlen;
139 /* Open or close TAG according to START_OR_END. */
141 insert_html_tag (start_or_end, tag)
145 if (!paragraph_is_open && (start_or_end == START))
147 /* Need to compensate for the <p> we are about to insert, or
148 else cm_xxx functions that call us will get wrong text
149 between START and END. */
150 adjust_braces_following (output_paragraph_offset, 3);
154 if (start_or_end != START)
160 /* Output an HTML <link> to the filename for NODE, including the
161 other string as extra attributes. */
163 add_link (nodename, attributes)
164 char *nodename, *attributes;
168 add_html_elt ("<link ");
169 add_word_args ("%s", attributes);
170 add_word_args (" href=\"");
171 add_anchor_name (nodename, 1);
172 add_word ("\"></a>\n");
176 /* Output NAME with characters escaped as appropriate for an anchor
177 name, i.e., escape URL special characters as %<n>. */
179 add_escaped_anchor_name (name)
182 for (; *name; name++)
186 else if (! URL_SAFE_CHAR (*name))
187 /* Cast so characters with the high bit set are treated as >128,
188 for example o-umlaut should be 246, not -10. */
189 add_word_args ("%%%x", (unsigned char) *name);
195 /* Insert the text for the name of a reference in an HTML anchor
196 appropriate for NODENAME. If HREF is nonzero, it will be
197 appropriate for a href= attribute, rather than name= i.e., including
198 the `#' if it's an internal reference. */
200 add_anchor_name (nodename, href)
207 add_url_name (nodename, href);
210 /* Always add NODENAME, so that the reference would pinpoint the
211 exact node on its file. This is so several nodes could share the
212 same file, in case of file-name clashes, but also for more
213 accurate browser positioning. */
214 if (strcasecmp (nodename, "(dir)") == 0)
215 /* Strip the parens, but keep the original letter-case. */
216 add_word_args ("%.3s", nodename + 1);
218 add_escaped_anchor_name (nodename);
221 /* Insert the text for the name of a reference in an HTML url, aprropriate
224 add_url_name (nodename, href)
228 add_nodename_to_filename (nodename, href);
231 /* Only allow [-0-9a-zA-Z_.] when nodifying filenames. This may
232 result in filename clashes; e.g.,
237 both map to Foo--.html. If that happens, cm_node will put all
238 the nodes whose file names clash on the same file. */
240 fix_filename (filename)
244 for (p = filename; *p; p++)
246 if (!(isalnum (*p) || strchr ("-._", *p)))
251 /* As we can't look-up a (forward-referenced) nodes' html filename
252 from the tentry, we take the easy way out. We assume that
253 nodenames are unique, and generate the html filename from the
254 nodename, that's always known. */
256 nodename_to_filename_1 (nodename, href)
262 char dirname[PATH_MAX];
264 if (strcasecmp (nodename, "Top") == 0)
266 /* We want to convert references to the Top node into
269 filename = xstrdup ("index.html"); /* "#Top" is added by our callers */
271 filename = xstrdup ("Top");
273 else if (strcasecmp (nodename, "(dir)") == 0)
274 /* We want to convert references to the (dir) node into
276 filename = xstrdup ("../index.html");
279 filename = xmalloc (PATH_MAX);
283 /* Check for external reference: ``(info-document)node-name''
284 Assume this node lives at: ``../info-document/node-name.html''
286 We need to handle the special case (sigh): ``(info-document)'',
287 ie, an external top-node, which should translate to:
288 ``../info-document/info-document.html'' */
291 if (*nodename == '(')
295 p = strchr (nodename, ')');
298 line_error (_("Invalid node name: `%s'"), nodename);
302 length = p - nodename - 1;
304 FILENAME_CMPN (p - 5, ".info", 5) == 0)
306 /* This is for DOS, and also for Windows and GNU/Linux
307 systems that might have Info files copied from a DOS 8+3
310 FILENAME_CMPN (p - 4, ".inf", 4) == 0)
312 strcpy (filename, "../");
313 strncpy (dirname, nodename + 1, length);
314 *(dirname + length) = '\0';
315 fix_filename (dirname);
316 strcat (filename, dirname);
317 strcat (filename, "/");
321 /* In the case of just (info-document), there will be nothing
322 remaining, and we will refer to ../info-document/, which will
324 strcat (filename, p);
328 fix_filename (filename + strlen (filename) - strlen (p));
329 strcat (filename, ".html");
333 /* Produce a file name suitable for the underlying filesystem. */
334 normalize_filename (filename);
337 /* We add ``#Nodified-filename'' anchor to external references to be
338 prepared for non-split HTML support. Maybe drop this. */
339 if (href && *dirname)
341 strcat (filename, "#");
342 strcat (filename, p);
344 fix_filename (filename + strlen (filename) - strlen (p));
351 /* If necessary, ie, if current filename != filename of node, output
354 add_nodename_to_filename (nodename, href)
358 /* for now, don't check: always output filename */
359 char *filename = nodename_to_filename_1 (nodename, href);
365 nodename_to_filename (nodename)
368 /* The callers of nodename_to_filename use the result to produce
369 <a href=, so call nodename_to_filename_1 with last arg non-zero. */
370 return nodename_to_filename_1 (nodename, 1);