1/* node.c -- nodes for Texinfo.
2   $Id: node.c,v 1.27 2004/12/20 23:56:07 karl Exp $
3
4   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
5   Foundation, Inc.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2, or (at your option)
10   any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software Foundation,
19   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21#include "system.h"
22#include "cmds.h"
23#include "files.h"
24#include "float.h"
25#include "footnote.h"
26#include "macro.h"
27#include "makeinfo.h"
28#include "node.h"
29#include "html.h"
30#include "sectioning.h"
31#include "insertion.h"
32#include "xml.h"
33
34/* See comments in node.h.  */
35NODE_REF *node_references = NULL;
36NODE_REF *node_node_references = NULL;
37TAG_ENTRY *tag_table = NULL;
38int node_number = -1;
39int node_order = 0;
40int current_section = 0;
41int outstanding_node = 0;
42
43/* Adding nodes, and making tags.  */
44
45/* Start a new tag table. */
46void
47init_tag_table (void)
48{
49  while (tag_table)
50    {
51      TAG_ENTRY *temp = tag_table;
52      free (temp->node);
53      free (temp->prev);
54      free (temp->next);
55      free (temp->up);
56      tag_table = tag_table->next_ent;
57      free (temp);
58    }
59}
60
61/* Write out the contents of the existing tag table.
62   INDIRECT_P says how to format the output (it depends on whether the
63   table is direct or indirect).  */
64static void
65write_tag_table_internal (int indirect_p)
66{
67  TAG_ENTRY *node;
68  int old_indent = no_indent;
69
70  if (xml)
71    {
72      flush_output ();
73      return;
74    }
75
76  no_indent = 1;
77  filling_enabled = 0;
78  must_start_paragraph = 0;
79  close_paragraph ();
80
81  if (!indirect_p)
82    {
83      no_indent = 1;
84      insert ('\n');
85    }
86
87  add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");
88
89  /* Do not collapse -- to -, etc., in node names.  */
90  in_fixed_width_font++;
91
92  for (node = tag_table; node; node = node->next_ent)
93    {
94      if (node->flags & TAG_FLAG_ANCHOR)
95        { /* This reference is to an anchor.  */
96          execute_string ("Ref: %s", node->node);
97        }
98      else
99        { /* This reference is to a node.  */
100          execute_string ("Node: %s", node->node);
101        }
102      add_word_args ("\177%d\n", node->position);
103    }
104
105  add_word ("\037\nEnd Tag Table\n");
106
107  /* Do not collapse -- to -, etc., in node names.  */
108  in_fixed_width_font--;
109
110  flush_output ();
111  no_indent = old_indent;
112}
113
114void
115write_tag_table (char *filename)
116{
117  output_stream = fopen (filename, "a");
118  if (!output_stream)
119    {
120      fs_error (filename);
121      return;
122    }
123
124  write_tag_table_internal (0); /* Not indirect. */
125
126  if (fclose (output_stream) != 0)
127    fs_error (filename);
128}
129
130static void
131write_tag_table_indirect (void)
132{
133  write_tag_table_internal (1);
134}
135
136/* Convert "top" and friends into "Top". */
137static void
138normalize_node_name (char *string)
139{
140  if (strcasecmp (string, "Top") == 0)
141    strcpy (string, "Top");
142}
143
144static char *
145get_node_token (int expand)
146{
147  char *string;
148
149  get_until_in_line (expand, ",", &string);
150
151  if (curchar () == ',')
152    input_text_offset++;
153
154  fix_whitespace (string);
155
156  /* Force all versions of "top" to be "Top". */
157  normalize_node_name (string);
158
159  return string;
160}
161
162/* Expand any macros and other directives in a node name, and
163   return the expanded name as an malloc'ed string.  */
164char *
165expand_node_name (char *node)
166{
167  char *result = node;
168
169  if (node)
170    {
171      /* Don't expand --, `` etc., in case somebody will want
172         to print the result.  */
173      in_fixed_width_font++;
174      result = expansion (node, 0);
175      in_fixed_width_font--;
176      fix_whitespace (result);
177      normalize_node_name (result);
178    }
179  return result;
180}
181
182/* Look up NAME in the tag table, and return the associated
183   tag_entry.  If the node is not in the table return NULL. */
184TAG_ENTRY *
185find_node (char *name)
186{
187  TAG_ENTRY *tag = tag_table;
188  char *expanded_name;
189  char n1 = name[0];
190
191  while (tag)
192    {
193      if (tag->node[0] == n1 && strcmp (tag->node, name) == 0)
194        return tag;
195      tag = tag->next_ent;
196    }
197
198  if (!expensive_validation)
199    return NULL;
200
201  /* Try harder.  Maybe TAG_TABLE has the expanded NAME, or maybe NAME
202     is expanded while TAG_TABLE has its unexpanded form.  This may
203     slow down the search, but if they want this feature, let them
204     pay!  If they want it fast, they should write every node name
205     consistently (either always expanded or always unexpaned).  */
206  expanded_name = expand_node_name (name);
207  for (tag = tag_table; tag; tag = tag->next_ent)
208    {
209      if (STREQ (tag->node, expanded_name))
210        break;
211      /* If the tag name doesn't have the command prefix, there's no
212         chance it could expand into anything but itself.  */
213      if (strchr (tag->node, COMMAND_PREFIX))
214        {
215          char *expanded_node = expand_node_name (tag->node);
216
217          if (STREQ (expanded_node, expanded_name))
218            {
219              free (expanded_node);
220              break;
221            }
222          free (expanded_node);
223        }
224    }
225  free (expanded_name);
226  return tag;
227}
228
229/* Look in the tag table for a node whose file name is FNAME, and
230   return the associated tag_entry.  If there's no such node in the
231   table, return NULL. */
232static TAG_ENTRY *
233find_node_by_fname (char *fname)
234{
235  TAG_ENTRY *tag = tag_table;
236  while (tag)
237    {
238      if (tag->html_fname && FILENAME_CMP (tag->html_fname, fname) == 0)
239	return tag;
240      tag = tag->next_ent;
241    }
242
243  return tag;
244}
245
246/* Remember next, prev, etc. references in a @node command, where we
247   don't care about most of the entries. */
248static void
249remember_node_node_reference (char *node)
250{
251  NODE_REF *temp = xmalloc (sizeof (NODE_REF));
252  int number;
253
254  if (!node) return;
255  temp->next = node_node_references;
256  temp->node = xstrdup (node);
257  temp->type = followed_reference;
258  number = number_of_node (node);
259  if (number)
260    temp->number = number;      /* Already assigned. */
261  else
262    {
263      node_number++;
264      temp->number = node_number;
265    }
266  node_node_references = temp;
267}
268
269/* Remember NODE and associates. */
270static void
271remember_node (char *node, char *prev, char *next, char *up,
272    int position, int line_no, char *fname, int flags)
273{
274  /* Check for existence of this tag already. */
275  if (validating)
276    {
277      TAG_ENTRY *tag = find_node (node);
278      if (tag)
279        {
280          line_error (_("Node `%s' previously defined at line %d"),
281                      node, tag->line_no);
282          return;
283        }
284    }
285
286  if (!(flags & TAG_FLAG_ANCHOR))
287    {
288      /* Make this the current node. */
289      current_node = node;
290    }
291
292  /* Add it to the list. */
293  {
294    int number = number_of_node (node);
295
296    TAG_ENTRY *new = xmalloc (sizeof (TAG_ENTRY));
297    new->node = node;
298    new->prev = prev;
299    new->next = next;
300    new->up = up;
301    new->position = position;
302    new->line_no = line_no;
303    new->filename = node_filename;
304    new->touched = 0;
305    new->flags = flags;
306    if (number)
307      new->number = number;     /* Already assigned. */
308    else
309      {
310        node_number++;
311        new->number = node_number;
312      }
313    if (fname)
314      new->html_fname = fname;
315    else
316      /* This happens for Top node under split-HTML, for example.  */
317      new->html_fname
318	= normalize_filename (filename_part (current_output_filename));
319    new->next_ent = tag_table;
320
321    /* Increment the order counter, and save it.  */
322    node_order++;
323    new->order = node_order;
324
325    tag_table = new;
326  }
327
328  if (html)
329    { /* Note the references to the next etc. nodes too.  */
330      remember_node_node_reference (next);
331      remember_node_node_reference (prev);
332      remember_node_node_reference (up);
333    }
334}
335
336/* Remember this node name for later validation use.  This is used to
337   remember menu references while reading the input file.  After the
338   output file has been written, if validation is on, then we use the
339   contents of `node_references' as a list of nodes to validate.  */
340void
341remember_node_reference (char *node, int line, enum reftype type)
342{
343  NODE_REF *temp = xmalloc (sizeof (NODE_REF));
344  int number = number_of_node (node);
345
346  temp->next = node_references;
347  temp->node = xstrdup (node);
348  temp->line_no = line;
349  temp->section = current_section;
350  temp->type = type;
351  temp->containing_node = xstrdup (current_node ? current_node : "");
352  temp->filename = node_filename;
353  if (number)
354    temp->number = number;      /* Already assigned. */
355  else
356    {
357      node_number++;
358      temp->number = node_number;
359    }
360
361  node_references = temp;
362}
363
364static void
365isolate_nodename (char *nodename)
366{
367  int i, c;
368  int paren_seen, paren;
369
370  if (!nodename)
371    return;
372
373  canon_white (nodename);
374  paren_seen = paren = i = 0;
375
376  if (*nodename == '.' || !*nodename)
377    {
378      *nodename = 0;
379      return;
380    }
381
382  if (*nodename == '(')
383    {
384      paren++;
385      paren_seen++;
386      i++;
387    }
388
389  for (; (c = nodename[i]); i++)
390    {
391      if (paren)
392        {
393          if (c == '(')
394            paren++;
395          else if (c == ')')
396            paren--;
397
398          continue;
399        }
400
401      /* If the character following the close paren is a space, then this
402         node has no more characters associated with it. */
403      if (c == '\t' ||
404          c == '\n' ||
405          c == ','  ||
406          ((paren_seen && nodename[i - 1] == ')') &&
407           (c == ' ' || c == '.')) ||
408          (c == '.' &&
409           ((!nodename[i + 1] ||
410             (cr_or_whitespace (nodename[i + 1])) ||
411             (nodename[i + 1] == ')')))))
412        break;
413    }
414  nodename[i] = 0;
415}
416
417/* This function gets called at the start of every line while inside a
418   menu.  It checks to see if the line starts with "* ", and if so and
419   REMEMBER_REF is nonzero, remembers the node reference as type
420   REF_TYPE that this menu refers to.  input_text_offset is at the \n
421   just before the menu line.  If REMEMBER_REF is zero, REF_TYPE is unused.  */
422#define MENU_STARTER "* "
423char *
424glean_node_from_menu (int remember_ref, enum reftype ref_type)
425{
426  int i, orig_offset = input_text_offset;
427  char *nodename;
428  char *line, *expanded_line;
429  char *old_input = input_text;
430  int old_size = input_text_length;
431
432  if (strncmp (&input_text[input_text_offset + 1],
433               MENU_STARTER,
434               strlen (MENU_STARTER)) != 0)
435    return NULL;
436  else
437    input_text_offset += strlen (MENU_STARTER) + 1;
438
439  /* The menu entry might include macro calls, so we need to expand them.  */
440  get_until ("\n", &line);
441  only_macro_expansion++;       /* only expand macros in menu entries */
442  expanded_line = expansion (line, 0);
443  only_macro_expansion--;
444  free (line);
445  input_text = expanded_line;
446  input_text_offset = 0;
447  input_text_length = strlen (expanded_line);
448
449  get_until_in_line (0, ":", &nodename);
450  if (curchar () == ':')
451    input_text_offset++;
452
453  if (curchar () != ':')
454    {
455      free (nodename);
456      get_until_in_line (0, "\n", &nodename);
457      isolate_nodename (nodename);
458    }
459
460  input_text = old_input;
461  input_text_offset = orig_offset;
462  input_text_length = old_size;
463  free (expanded_line);
464  fix_whitespace (nodename);
465  normalize_node_name (nodename);
466  i = strlen (nodename);
467  if (i && nodename[i - 1] == ':')
468    nodename[i - 1] = 0;
469
470  if (remember_ref)
471    remember_node_reference (nodename, line_number, ref_type);
472
473  return nodename;
474}
475
476/* Set the name of the current output file.  */
477void
478set_current_output_filename (const char *fname)
479{
480  if (current_output_filename)
481    free (current_output_filename);
482  current_output_filename = xstrdup (fname);
483}
484
485
486/* Output the <a name="..."></a> constructs for NODE.  We output both
487   the new-style conversion and the old-style, if they are different.
488   See comments at `add_escaped_anchor_name' in html.c.  */
489
490static void
491add_html_names (char *node)
492{
493  char *tem = expand_node_name (node);
494  char *otem = xstrdup (tem);
495
496  /* Determine if the old and new schemes come up with different names;
497     only output the old scheme if that is so.  We don't want to output
498     the same name twice.  */
499  canon_white (otem);
500  {
501    char *optr = otem;
502    int need_old = 0;
503
504    for (; *optr; optr++)
505      {
506        if (!cr_or_whitespace (*optr) && !URL_SAFE_CHAR (*optr))
507          {
508            need_old = 1;
509            break;
510          }
511      }
512
513    if (need_old)
514      {
515        add_word ("<a name=\"");
516        add_anchor_name (otem, -1);  /* old anchor name conversion */
517        add_word ("\"></a>\n");
518      }
519    free (otem);
520  }
521
522  /* Always output the new scheme.  */
523  canon_white (tem);
524  add_word ("<a name=\"");
525  add_anchor_name (tem, 0);
526  add_word ("\"></a>\n");
527
528  free (tem);
529}
530
531
532/* The order is: nodename, nextnode, prevnode, upnode.
533   If all of the NEXT, PREV, and UP fields are empty, they are defaulted.
534   You must follow a node command which has those fields defaulted
535   with a sectioning command (e.g., @chapter) giving the "level" of that node.
536   It is an error not to do so.
537   The defaults come from the menu in this node's parent. */
538void
539cm_node (void)
540{
541  static long epilogue_len = 0L;
542  char *node, *prev, *next, *up;
543  int new_node_pos, defaulting, this_section;
544  int no_warn = 0;
545  char *fname_for_this_node = NULL;
546  char *tem;
547  TAG_ENTRY *tag = NULL;
548
549  if (strcmp (command, "nwnode") == 0)
550    no_warn = TAG_FLAG_NO_WARN;
551
552  /* Get rid of unmatched brace arguments from previous commands. */
553  discard_braces ();
554
555  /* There also might be insertions left lying around that haven't been
556     ended yet.  Do that also. */
557  discard_insertions (1);
558
559  if (!html && !already_outputting_pending_notes)
560    {
561      close_paragraph ();
562      output_pending_notes ();
563    }
564
565  new_node_pos = output_position;
566
567  if (macro_expansion_output_stream && !executing_string)
568    append_to_expansion_output (input_text_offset + 1);
569
570  /* Do not collapse -- to -, etc., in node names.  */
571  in_fixed_width_font++;
572
573  /* While expanding the @node line, leave any non-macros
574     intact, so that the macro-expanded output includes them.  */
575  only_macro_expansion++;
576  node = get_node_token (1);
577  only_macro_expansion--;
578  next = get_node_token (0);
579  prev = get_node_token (0);
580  up = get_node_token (0);
581
582  if (html && splitting
583      /* If there is a Top node, it always goes into index.html.  So
584	 don't start a new HTML file for Top.  */
585      && (top_node_seen || strcasecmp (node, "Top") != 0))
586    {
587      /* We test *node here so that @node without a valid name won't
588	 start a new file name with a bogus name such as ".html".
589	 This could happen if we run under "--force", where we cannot
590	 simply bail out.  Continuing to use the same file sounds like
591	 the best we can do in such cases.  */
592      if (current_output_filename && output_stream && *node)
593	{
594	  char *fname_for_prev_node;
595
596	  if (current_node)
597	    {
598	      /* NOTE: current_node at this point still holds the name
599		 of the previous node.  */
600	      tem = expand_node_name (current_node);
601	      fname_for_prev_node = nodename_to_filename (tem);
602	      free (tem);
603	    }
604	  else /* could happen if their top node isn't named "Top" */
605	    fname_for_prev_node = filename_part (current_output_filename);
606	  tem = expand_node_name (node);
607	  fname_for_this_node = nodename_to_filename (tem);
608	  free (tem);
609	  /* Don't close current output file, if next output file is
610             to have the same name.  This may happen at top level, or
611             if two nodes produce the same file name under --split.  */
612	  if (FILENAME_CMP (fname_for_this_node, fname_for_prev_node) != 0)
613	    {
614	      long pos1 = 0;
615
616	      /* End the current split output file. */
617	      close_paragraph ();
618	      output_pending_notes ();
619	      start_paragraph ();
620	      /* Compute the length of the HTML file's epilogue.  We
621		 cannot know the value until run time, due to the
622		 text/binary nuisance on DOS/Windows platforms, where
623		 2 `\r' characters could be added to the epilogue when
624		 it is written in text mode.  */
625	      if (epilogue_len == 0)
626		{
627		  flush_output ();
628		  pos1 = ftell (output_stream);
629		}
630	      add_word ("</body></html>\n");
631	      close_paragraph ();
632	      if (epilogue_len == 0)
633		epilogue_len = ftell (output_stream) - pos1;
634	      fclose (output_stream);
635	      output_stream = NULL;
636              output_position = 0;
637	      tag = find_node_by_fname (fname_for_this_node);
638	    }
639	  free (fname_for_prev_node);
640	}
641    }
642
643  filling_enabled = indented_fill = 0;
644  if (!html || (html && splitting))
645    current_footnote_number = 1;
646
647  if (verbose_mode)
648    printf (_("Formatting node %s...\n"), node);
649
650  if (macro_expansion_output_stream && !executing_string)
651    remember_itext (input_text, input_text_offset);
652
653  /* Reset the line number in each node for Info output, so that
654     index entries will save the line numbers of parent node.  */
655  node_line_number = 0;
656
657  no_indent = 1;
658  if (xml)
659    {
660      xml_begin_document (current_output_filename);
661      xml_begin_node ();
662      if (!docbook)
663	{
664	  xml_insert_element (NODENAME, START);
665	  if (macro_expansion_output_stream && !executing_string)
666	    me_execute_string (node);
667	  else
668	    execute_string ("%s", node);
669	  xml_insert_element (NODENAME, END);
670	}
671      else
672	xml_node_id = xml_id (node);
673    }
674  else if (!no_headers && !html)
675    {
676      /* Emacs Info reader cannot grok indented escape sequence.  */
677      kill_self_indent (-1);
678
679      add_word_args ("\037\nFile: %s,  Node: ", pretty_output_filename);
680
681      if (macro_expansion_output_stream && !executing_string)
682        me_execute_string (node);
683      else
684        execute_string ("%s", node);
685      filling_enabled = indented_fill = 0;
686    }
687
688  /* Check for defaulting of this node's next, prev, and up fields. */
689  defaulting = (*next == 0 && *prev == 0 && *up == 0);
690
691  this_section = what_section (input_text + input_text_offset, NULL);
692
693  /* If we are defaulting, then look at the immediately following
694     sectioning command (error if none) to determine the node's
695     level.  Find the node that contains the menu mentioning this node
696     that is one level up (error if not found).  That node is the "Up"
697     of this node.  Default the "Next" and "Prev" from the menu. */
698  if (defaulting)
699    {
700      NODE_REF *last_ref = NULL;
701      NODE_REF *ref = node_references;
702
703      if (this_section < 0 && !STREQ (node, "Top"))
704        {
705          char *polite_section_name = "top";
706          int i;
707
708          for (i = 0; section_alist[i].name; i++)
709            if (section_alist[i].level == current_section + 1)
710              {
711                polite_section_name = section_alist[i].name;
712                break;
713              }
714
715          line_error
716            (_("Node `%s' requires a sectioning command (e.g., %c%s)"),
717             node, COMMAND_PREFIX, polite_section_name);
718        }
719      else
720        {
721          if (strcmp (node, "Top") == 0)
722            {
723              /* Default the NEXT pointer to be the first menu item in
724                 this node, if there is a menu in this node.  We have to
725                 try very hard to find the menu, as it may be obscured
726                 by execution_strings which are on the filestack.  For
727                 every member of the filestack which has a FILENAME
728                 member which is identical to the current INPUT_FILENAME,
729                 search forward from that offset. */
730              int saved_input_text_offset = input_text_offset;
731              int saved_input_text_length = input_text_length;
732              char *saved_input_text = input_text;
733              FSTACK *next_file = filestack;
734
735              int orig_offset, orig_size;
736
737              int bye_offset = search_forward ("\n@bye", input_text_offset);
738
739              /* No matter what, make this file point back at `(dir)'. */
740              free (up);
741              up = xstrdup ("(dir)"); /* html fixxme */
742
743              while (1)
744                {
745                  orig_offset = input_text_offset;
746                  orig_size =
747                    search_forward (node_search_string, orig_offset);
748
749                  if (orig_size < 0)
750                    orig_size = input_text_length;
751
752                  input_text_offset = search_forward ("\n@menu", orig_offset);
753                  if (input_text_offset > -1
754                      && (bye_offset > -1 && input_text_offset < bye_offset)
755                      && cr_or_whitespace (input_text[input_text_offset + 6]))
756                    {
757                      char *nodename_from_menu = NULL;
758
759                      input_text_offset =
760                        search_forward ("\n* ", input_text_offset);
761
762                      if (input_text_offset != -1)
763                        nodename_from_menu = glean_node_from_menu (0, 0);
764
765                      if (nodename_from_menu)
766                        {
767                          free (next);
768                          next = nodename_from_menu;
769                          break;
770                        }
771                    }
772
773                  /* We got here, so it hasn't been found yet.  Try
774                     the next file on the filestack if there is one. */
775                  if (next_file
776                      && FILENAME_CMP (next_file->filename, input_filename)
777                          == 0)
778                    {
779                      input_text = next_file->text;
780                      input_text_offset = next_file->offset;
781                      input_text_length = next_file->size;
782                      next_file = next_file->next;
783                    }
784                  else
785                    { /* No more input files to check. */
786                      break;
787                    }
788                }
789
790              input_text = saved_input_text;
791              input_text_offset = saved_input_text_offset;
792              input_text_length = saved_input_text_length;
793            }
794        }
795
796      /* Fix the level of the menu references in the Top node, iff it
797         was declared with @top, and no subsequent reference was found. */
798      if (top_node_seen && !non_top_node_seen)
799        {
800          /* Then this is the first non-@top node seen. */
801          int level;
802
803          level = set_top_section_level (this_section - 1);
804          non_top_node_seen = 1;
805
806          while (ref)
807            {
808              if (ref->section == level)
809                ref->section = this_section - 1;
810              ref = ref->next;
811            }
812
813          ref = node_references;
814        }
815
816      while (ref)
817        {
818          if (ref->section == (this_section - 1)
819              && ref->type == menu_reference
820              && strcmp (ref->node, node) == 0)
821            {
822              char *containing_node = ref->containing_node;
823
824              free (up);
825              up = xstrdup (containing_node);
826
827              if (last_ref
828                  && last_ref->type == menu_reference
829                  && strcmp (last_ref->containing_node, containing_node) == 0)
830                {
831                  free (next);
832                  next = xstrdup (last_ref->node);
833                }
834
835              while (ref->section == this_section - 1
836                     && ref->next
837                     && ref->next->type != menu_reference)
838                ref = ref->next;
839
840              if (ref->next && ref->type == menu_reference
841                  && strcmp (ref->next->containing_node, containing_node) == 0)
842                {
843                  free (prev);
844                  prev = xstrdup (ref->next->node);
845                }
846              else if (!ref->next
847                       && strcasecmp (ref->containing_node, "Top") == 0)
848                {
849                  free (prev);
850                  prev = xstrdup (ref->containing_node);
851                }
852              break;
853            }
854          last_ref = ref;
855          ref = ref->next;
856        }
857    }
858
859  /* Insert the correct args if we are expanding macros, and the node's
860     pointers weren't defaulted. */
861  if (macro_expansion_output_stream && !executing_string && !defaulting)
862    {
863      char *temp;
864      int op_orig = output_paragraph_offset;
865      int meta_pos_orig = meta_char_pos;
866      int extra = html ? strlen (node) : 0;
867
868      temp = xmalloc (7 + extra + strlen (next) + strlen (prev) + strlen (up));
869      sprintf (temp, "%s, %s, %s, %s", html ? node : "", next, prev, up);
870      me_execute_string (temp);
871      free (temp);
872
873      output_paragraph_offset = op_orig;
874      meta_char_pos = meta_pos_orig;
875    }
876
877  if (!*node)
878    {
879      line_error (_("No node name specified for `%c%s' command"),
880                  COMMAND_PREFIX, command);
881      free (node);
882      free (next); next = NULL;
883      free (prev); prev= NULL;
884      free (up);   up = NULL;
885      node_number++;            /* else it doesn't get bumped */
886    }
887  else
888    {
889      if (!*next) { free (next); next = NULL; }
890      if (!*prev) { free (prev); prev = NULL; }
891      if (!*up)   { free (up);   up = NULL;   }
892      remember_node (node, prev, next, up, new_node_pos, line_number,
893		     fname_for_this_node, no_warn);
894      outstanding_node = 1;
895    }
896
897  if (html)
898    {
899      if (splitting && *node && output_stream == NULL)
900        {
901	  char *dirname;
902	  char filename[PATH_MAX];
903
904	  dirname = pathname_part (current_output_filename);
905	  strcpy (filename, dirname);
906	  strcat (filename, fname_for_this_node);
907	  free (dirname);
908
909	  /* See if the node name converted to a file name clashes
910	     with other nodes or anchors.  If it clashes with an
911	     anchor, we complain and nuke that anchor's file.  */
912	  if (!tag)
913	    {
914	      output_stream = fopen (filename, "w");
915	      html_output_head_p = 0; /* so that we generate HTML preamble */
916	      html_output_head ();
917	    }
918	  else if ((tag->flags & TAG_FLAG_ANCHOR) != 0)
919	    {
920	      line_error (_("Anchor `%s' and node `%s' map to the same file name"),
921			  tag->node, node);
922	      file_line_error (tag->filename, tag->line_no,
923			       _("This @anchor command ignored; references to it will not work"));
924	      file_line_error (tag->filename, tag->line_no,
925			       _("Rename this anchor or use the `--no-split' option"));
926	      /* Nuke the file name recorded in anchor's tag.
927		 Since we are about to nuke the file itself, we
928		 don't want find_node_by_fname to consider this
929		 anchor anymore.  */
930	      free (tag->html_fname);
931	      tag->html_fname = NULL;
932	      output_stream = fopen (filename, "w");
933	      html_output_head_p = 0; /* so that we generate HTML preamble */
934	      html_output_head ();
935	    }
936	  else
937	    {
938	      /* This node's file name clashes with another node.
939		 We put them both on the same file.  */
940	      output_stream = fopen (filename, "r+");
941	      if (output_stream)
942		{
943		  static char html_end[] = "</body></html>\n";
944		  char end_line[sizeof(html_end)];
945		  int fpos = fseek (output_stream, -epilogue_len,
946				    SEEK_END);
947
948		  if (fpos < 0
949		      || fgets (end_line, sizeof (html_end),
950				output_stream) == NULL
951		      /* Paranoia: did someone change the way HTML
952			 files are finished up?  */
953		      || strcasecmp (end_line, html_end) != 0)
954		    {
955		      line_error (_("Unexpected string at end of split-HTML file `%s'"),
956				  fname_for_this_node);
957		      fclose (output_stream);
958		      xexit (1);
959		    }
960		  fseek (output_stream, -epilogue_len, SEEK_END);
961		}
962	    }
963          if (output_stream == NULL)
964            {
965              fs_error (filename);
966              xexit (1);
967            }
968          set_current_output_filename (filename);
969        }
970
971      if (!splitting && no_headers)
972	{ /* cross refs need a name="#anchor" even if not writing headers */
973          add_html_names (node);
974	}
975
976      if (splitting || !no_headers)
977        { /* Navigation bar. */
978          add_html_block_elt ("<div class=\"node\">\n");
979          /* The <p> avoids the links area running on with old Lynxen. */
980          add_word_args ("<p>%s\n", splitting ? "" : "<hr>");
981
982          /* In the split HTML case, the filename is wrong for the
983             old-style converted names, but we'll add them anyway, for
984             consistency.  (And we need them in the normal (not
985             no_headers) nonsplit case.)  */
986          add_html_names (node);
987
988          if (next)
989            {
990              tem = expansion (next, 0);
991	      add_word ((char *) _("Next:"));
992              add_word ("&nbsp;");
993
994	      add_word ("<a rel=\"next\" accesskey=\"n\" href=\"");
995	      add_anchor_name (tem, 1);
996              tem = escape_string (tem);
997	      add_word_args ("\">%s</a>", tem);
998
999              free (tem);
1000
1001	      if (prev || up)
1002		add_word (",\n");
1003            }
1004          if (prev)
1005            {
1006              tem = expansion (prev, 0);
1007	      add_word ((char *) _("Previous:"));
1008              add_word ("&nbsp;");
1009	      add_word ("<a rel=\"previous\" accesskey=\"p\" href=\"");
1010	      add_anchor_name (tem, 1);
1011              tem = escape_string (tem);
1012	      add_word_args ("\">%s</a>", tem);
1013              free (tem);
1014
1015	      if (up)
1016		add_word (",\n");
1017            }
1018          if (up)
1019            {
1020              tem = expansion (up, 0);
1021	      add_word ((char *) _("Up:"));
1022              add_word ("&nbsp;");
1023	      add_word ("<a rel=\"up\" accesskey=\"u\" href=\"");
1024	      add_anchor_name (tem, 1);
1025              tem = escape_string (tem);
1026	      add_word_args ("\">%s</a>", tem);
1027              free (tem);
1028            }
1029          /* html fixxme: we want a `top' or `contents' link here.  */
1030
1031          add_word_args ("\n%s\n", splitting ? "<hr>" : "");
1032      	  add_word ("</div>\n");
1033        }
1034    }
1035  else if (docbook)
1036    ;
1037  else if (xml)
1038    {
1039      if (next)
1040	{
1041	  xml_insert_element (NODENEXT, START);
1042	  execute_string ("%s", next);
1043	  xml_insert_element (NODENEXT, END);
1044	}
1045      if (prev)
1046	{
1047	  xml_insert_element (NODEPREV, START);
1048	  execute_string ("%s", prev);
1049	  xml_insert_element (NODEPREV, END);
1050	}
1051      if (up)
1052	{
1053	  xml_insert_element (NODEUP, START);
1054	  execute_string ("%s", up);
1055	  xml_insert_element (NODEUP, END);
1056	}
1057    }
1058  else if (!no_headers)
1059    {
1060      if (macro_expansion_output_stream)
1061        me_inhibit_expansion++;
1062
1063      /* These strings are not translatable.  */
1064      if (next)
1065        {
1066          execute_string (",  Next: %s", next);
1067          filling_enabled = indented_fill = 0;
1068        }
1069      if (prev)
1070        {
1071          execute_string (",  Prev: %s", prev);
1072          filling_enabled = indented_fill = 0;
1073        }
1074      if (up)
1075        {
1076          execute_string (",  Up: %s", up);
1077          filling_enabled = indented_fill = 0;
1078        }
1079      if (macro_expansion_output_stream)
1080        me_inhibit_expansion--;
1081    }
1082
1083  close_paragraph ();
1084  no_indent = 0;
1085
1086  /* Change the section only if there was a sectioning command. */
1087  if (this_section >= 0)
1088    current_section = this_section;
1089
1090  if (current_node && STREQ (current_node, "Top"))
1091    top_node_seen = 1;
1092
1093  filling_enabled = 1;
1094  in_fixed_width_font--;
1095}
1096
1097/* Cross-reference target at an arbitrary spot.  */
1098void
1099cm_anchor (int arg)
1100{
1101  char *anchor;
1102  char *fname_for_anchor = NULL;
1103
1104  if (arg == END)
1105    return;
1106
1107  /* Parse the anchor text.  */
1108  anchor = get_xref_token (1);
1109
1110  /* Force all versions of "top" to be "Top". */
1111  normalize_node_name (anchor);
1112
1113  /* In HTML mode, need to actually produce some output.  */
1114  if (html)
1115    {
1116      /* If this anchor is at the beginning of a new paragraph, make
1117	 sure a new paragraph is indeed started.  */
1118      if (!paragraph_is_open)
1119	{
1120	  if (!executing_string && html)
1121	    html_output_head ();
1122	  start_paragraph ();
1123	  if (!in_fixed_width_font || in_menu || in_detailmenu)
1124	    {
1125	      insert_string ("<p>");
1126	      in_paragraph = 1;
1127	    }
1128	}
1129      add_word ("<a name=\"");
1130      add_anchor_name (anchor, 0);
1131      add_word ("\"></a>");
1132      if (splitting)
1133	{
1134	  /* If we are splitting, cm_xref will produce a reference to
1135	     a file whose name is derived from the anchor name.  So we
1136	     must create a file when we see an @anchor, otherwise
1137	     xref's to anchors won't work.  The file we create simply
1138	     redirects to the file of this anchor's node.  */
1139	  TAG_ENTRY *tag;
1140
1141	  fname_for_anchor = nodename_to_filename (anchor);
1142	  /* See if the anchor name converted to a file name clashes
1143	     with other anchors or nodes.  */
1144	  tag = find_node_by_fname (fname_for_anchor);
1145	  if (tag)
1146	    {
1147	      if ((tag->flags & TAG_FLAG_ANCHOR) != 0)
1148		line_error (_("Anchors `%s' and `%s' map to the same file name"),
1149			    anchor, tag->node);
1150	      else
1151		line_error (_("Anchor `%s' and node `%s' map to the same file name"),
1152			    anchor, tag->node);
1153	      line_error (_("@anchor command ignored; references to it will not work"));
1154	      line_error (_("Rename this anchor or use the `--no-split' option"));
1155	      free (fname_for_anchor);
1156	      /* We will not be creating a file for this anchor, so
1157		 set its name to NULL, so that remember_node stores a
1158		 NULL and find_node_by_fname won't consider this
1159		 anchor for clashes.  */
1160	      fname_for_anchor = NULL;
1161	    }
1162	  else
1163	    {
1164	      char *dirname, *p;
1165	      char filename[PATH_MAX];
1166	      FILE *anchor_stream;
1167
1168	      dirname = pathname_part (current_output_filename);
1169	      strcpy (filename, dirname);
1170	      strcat (filename, fname_for_anchor);
1171	      free (dirname);
1172
1173	      anchor_stream = fopen (filename, "w");
1174	      if (anchor_stream == NULL)
1175		{
1176		  fs_error (filename);
1177		  xexit (1);
1178		}
1179	      /* The HTML magic below will cause the browser to
1180		 immediately go to the anchor's node's file.  Lynx
1181		 seems not to support this redirection, but it looks
1182		 like a bug in Lynx, and they can work around it by
1183		 clicking on the link once more.  */
1184	      fputs ("<meta http-equiv=\"refresh\" content=\"0; url=",
1185		     anchor_stream);
1186	      /* Make the indirect link point to the current node's
1187		 file and anchor's "<a name" label.  If we don't have
1188		 a valid node name, refer to the current output file
1189		 instead.  */
1190	      if (current_node && *current_node)
1191		{
1192		  char *fn, *tem;
1193
1194		  tem = expand_node_name (current_node);
1195		  fn = nodename_to_filename (tem);
1196		  free (tem);
1197		  fputs (fn, anchor_stream);
1198		  free (fn);
1199		}
1200	      else
1201		{
1202		  char *base = filename_part (current_output_filename);
1203
1204		  fputs (base, anchor_stream);
1205		  free (base);
1206		}
1207	      fputs ("#", anchor_stream);
1208	      for (p = anchor; *p; p++)
1209		{
1210		  if (*p == '&')
1211		    fputs ("&amp;", anchor_stream);
1212		  else if (!URL_SAFE_CHAR (*p))
1213		    fprintf (anchor_stream, "%%%x", (unsigned char) *p);
1214		  else
1215		    fputc (*p, anchor_stream);
1216		}
1217	      fputs ("\">\n", anchor_stream);
1218	      fclose (anchor_stream);
1219	    }
1220	}
1221    }
1222  else if (xml)
1223    {
1224      xml_insert_element_with_attribute (ANCHOR, START, "name=\"%s\"", anchor);
1225      xml_insert_element (ANCHOR, END);
1226    }
1227  /* Save it in the tag table.  */
1228  remember_node (anchor, NULL, NULL, NULL,
1229                 output_position + output_paragraph_offset,
1230                 line_number, fname_for_anchor, TAG_FLAG_ANCHOR);
1231}
1232
1233/* Find NODE in REF_LIST. */
1234static NODE_REF *
1235find_node_reference (char *node, NODE_REF *ref_list)
1236{
1237  NODE_REF *orig_ref_list = ref_list;
1238  char *expanded_node;
1239
1240  while (ref_list)
1241    {
1242      if (strcmp (node, ref_list->node) == 0)
1243        break;
1244      ref_list = ref_list->next;
1245    }
1246
1247  if (ref_list || !expensive_validation)
1248    return ref_list;
1249
1250  /* Maybe NODE is not expanded yet.  This may be SLOW.  */
1251  expanded_node = expand_node_name (node);
1252  for (ref_list = orig_ref_list; ref_list; ref_list = ref_list->next)
1253    {
1254      if (STREQ (expanded_node, ref_list->node))
1255        break;
1256      if (strchr (ref_list->node, COMMAND_PREFIX))
1257        {
1258          char *expanded_ref = expand_node_name (ref_list->node);
1259
1260          if (STREQ (expanded_node, expanded_ref))
1261            {
1262              free (expanded_ref);
1263              break;
1264            }
1265          free (expanded_ref);
1266        }
1267    }
1268  free (expanded_node);
1269  return ref_list;
1270}
1271
1272void
1273free_node_references (void)
1274{
1275  NODE_REF *list, *temp;
1276
1277  list = node_references;
1278
1279  while (list)
1280    {
1281      temp = list;
1282      free (list->node);
1283      free (list->containing_node);
1284      list = list->next;
1285      free (temp);
1286    }
1287  node_references = NULL;
1288}
1289
1290void
1291free_node_node_references (void)
1292{
1293  NODE_REF *list, *temp;
1294
1295  list = node_references;
1296
1297  while (list)
1298    {
1299      temp = list;
1300      free (list->node);
1301      list = list->next;
1302      free (temp);
1303    }
1304  node_node_references = NULL;
1305}
1306
1307/* Return the number assigned to a named node in either the tag_table
1308   or node_references list or zero if no number has been assigned. */
1309int
1310number_of_node (char *node)
1311{
1312  NODE_REF *temp_ref;
1313  TAG_ENTRY *temp_node = find_node (node);
1314
1315  if (temp_node)
1316    return temp_node->number;
1317  else if ((temp_ref = find_node_reference (node, node_references)))
1318    return temp_ref->number;
1319  else if ((temp_ref = find_node_reference (node, node_node_references)))
1320    return temp_ref->number;
1321  else
1322    return 0;
1323}
1324
1325/* validation */
1326
1327/* Return 1 if TAG (at LINE) correctly validated, or 0 if not.
1328   LABEL is the (translated) description of the type of reference --
1329   Menu, Cross, Next, etc.  */
1330
1331static int
1332validate (char *tag, int line, const char *label)
1333{
1334  TAG_ENTRY *result;
1335
1336  /* If there isn't a tag to verify, or if the tag is in another file,
1337     then it must be okay. */
1338  if (!tag || !*tag || *tag == '(')
1339    return 1;
1340
1341  /* Otherwise, the tag must exist. */
1342  result = find_node (tag);
1343
1344  if (!result)
1345    {
1346      line_number = line;
1347      line_error (_("%s reference to nonexistent node `%s' (perhaps incorrect sectioning?)"), label, tag);
1348      return 0;
1349    }
1350  result->touched++;
1351  return 1;
1352}
1353
1354/* The strings here are followed in the message by `reference to...' in
1355   the `validate' routine.  They are only used in messages, thus are
1356   translated.  */
1357static const char *
1358reftype_type_string (enum reftype type)
1359{
1360  switch (type)
1361    {
1362    case menu_reference:
1363      return _("Menu");
1364    case followed_reference:
1365      return _("Cross");
1366    default:
1367      return "Internal-bad-reference-type";
1368    }
1369}
1370
1371static void
1372validate_other_references (NODE_REF *ref_list)
1373{
1374  char *old_input_filename = input_filename;
1375
1376  while (ref_list)
1377    {
1378      input_filename = ref_list->filename;
1379      validate (ref_list->node, ref_list->line_no,
1380                reftype_type_string (ref_list->type));
1381      ref_list = ref_list->next;
1382    }
1383  input_filename = old_input_filename;
1384}
1385
1386/* Validation of an info file.
1387   Scan through the list of tag entries touching the Prev, Next, and Up
1388   elements of each.  It is an error not to be able to touch one of them,
1389   except in the case of external node references, such as "(DIR)".
1390
1391   If the Prev is different from the Up,
1392   then the Prev node must have a Next pointing at this node.
1393
1394   Every node except Top must have an Up.
1395   The Up node must contain some sort of reference, other than a Next,
1396   to this node.
1397
1398   If the Next is different from the Next of the Up,
1399   then the Next node must have a Prev pointing at this node. */
1400void
1401validate_file (TAG_ENTRY *tag_table)
1402{
1403  char *old_input_filename = input_filename;
1404  TAG_ENTRY *tags = tag_table;
1405
1406  while (tags)
1407    {
1408      TAG_ENTRY *temp_tag;
1409      char *tem1, *tem2;
1410
1411      input_filename = tags->filename;
1412      line_number = tags->line_no;
1413
1414      /* If this is a "no warn" node, don't validate it in any way. */
1415      if (tags->flags & TAG_FLAG_NO_WARN)
1416        {
1417          tags = tags->next_ent;
1418          continue;
1419        }
1420
1421      /* If this node has a Next, then make sure that the Next exists. */
1422      if (tags->next)
1423        {
1424          validate (tags->next, tags->line_no, _("Next"));
1425
1426          /* If the Next node exists, and there is no Up, then make sure
1427             that the Prev of the Next points back.  But do nothing if
1428             we aren't supposed to issue warnings about this node. */
1429          temp_tag = find_node (tags->next);
1430          if (temp_tag && !(temp_tag->flags & TAG_FLAG_NO_WARN))
1431            {
1432              char *prev = temp_tag->prev;
1433              int you_lose = !prev || !STREQ (prev, tags->node);
1434
1435              if (you_lose && expensive_validation)
1436                {
1437                  tem1 = expand_node_name (prev);
1438                  tem2 = expand_node_name (tags->node);
1439
1440                  if (tem1 && tem2 && STREQ (tem1, tem2))
1441                    you_lose = 0;
1442                  free (tem1);
1443                  free (tem2);
1444                }
1445              if (you_lose)
1446                {
1447                  line_error (_("Next field of node `%s' not pointed to (perhaps incorrect sectioning?)"),
1448                              tags->node);
1449                  file_line_error (temp_tag->filename, temp_tag->line_no,
1450				   _("This node (%s) has the bad Prev"),
1451				   temp_tag->node);
1452                  temp_tag->flags |= TAG_FLAG_PREV_ERROR;
1453                }
1454            }
1455        }
1456
1457      /* Validate the Prev field if there is one, and we haven't already
1458         complained about it in some way.  You don't have to have a Prev
1459         field at this stage. */
1460      if (!(tags->flags & TAG_FLAG_PREV_ERROR) && tags->prev)
1461        {
1462          int valid_p = validate (tags->prev, tags->line_no, _("Prev"));
1463
1464          if (!valid_p)
1465            tags->flags |= TAG_FLAG_PREV_ERROR;
1466          else
1467            { /* If the Prev field is not the same as the Up field,
1468                 then the node pointed to by the Prev field must have
1469                 a Next field which points to this node. */
1470              int prev_equals_up = !tags->up || STREQ (tags->prev, tags->up);
1471
1472              if (!prev_equals_up && expensive_validation)
1473                {
1474                  tem1 = expand_node_name (tags->prev);
1475                  tem2 = expand_node_name (tags->up);
1476                  prev_equals_up = STREQ (tem1, tem2);
1477                  free (tem1);
1478                  free (tem2);
1479                }
1480              if (!prev_equals_up)
1481                {
1482                  temp_tag = find_node (tags->prev);
1483
1484                  /* If we aren't supposed to issue warnings about the
1485                     target node, do nothing. */
1486                  if (!temp_tag || (temp_tag->flags & TAG_FLAG_NO_WARN))
1487                    /* Do nothing. */ ;
1488                  else
1489                    {
1490                      int you_lose = !temp_tag->next
1491                        || !STREQ (temp_tag->next, tags->node);
1492
1493                      if (temp_tag->next && you_lose && expensive_validation)
1494                        {
1495                          tem1 = expand_node_name (temp_tag->next);
1496                          tem2 = expand_node_name (tags->node);
1497                          if (STREQ (tem1, tem2))
1498                            you_lose = 0;
1499                          free (tem1);
1500                          free (tem2);
1501                        }
1502                      if (you_lose)
1503                        {
1504                          line_error
1505                            (_("Prev field of node `%s' not pointed to"),
1506                             tags->node);
1507                          file_line_error (temp_tag->filename,
1508					   temp_tag->line_no,
1509					   _("This node (%s) has the bad Next"),
1510					   temp_tag->node);
1511                          temp_tag->flags |= TAG_FLAG_NEXT_ERROR;
1512                        }
1513                    }
1514                }
1515            }
1516        }
1517
1518      if (!tags->up
1519          && !(tags->flags & TAG_FLAG_ANCHOR)
1520          && strcasecmp (tags->node, "Top") != 0)
1521        line_error (_("`%s' has no Up field (perhaps incorrect sectioning?)"), tags->node);
1522      else if (tags->up)
1523        {
1524          int valid_p = validate (tags->up, tags->line_no, _("Up"));
1525
1526          /* If node X has Up: Y, then warn if Y fails to have a menu item
1527             or note pointing at X, if Y isn't of the form "(Y)". */
1528          if (valid_p && *tags->up != '(')
1529            {
1530              NODE_REF *nref;
1531              NODE_REF *tref = NULL;
1532              NODE_REF *list = node_references;
1533
1534              for (;;)
1535                {
1536                  nref = find_node_reference (tags->node, list);
1537                  if (!nref)
1538                    break;
1539
1540                  if (strcmp (nref->containing_node, tags->up) == 0)
1541                    {
1542                      if (nref->type != menu_reference)
1543                        {
1544                          tref = nref;
1545                          list = nref->next;
1546                        }
1547                      else
1548                        break;
1549                    }
1550                  list = nref->next;
1551                }
1552
1553              if (!nref)
1554                {
1555		  if (!tref && expensive_validation)
1556		    {
1557		      /* Sigh...  This might be AWFULLY slow, but if
1558		         they want this feature, they'll have to pay!
1559		         We do all the loop again expanding each
1560		         containing_node reference as we go.  */
1561		      char *tags_up = expand_node_name (tags->up);
1562		      char *tem;
1563
1564		      list = node_references;
1565
1566		      for (;;)
1567			{
1568			  nref = find_node_reference (tags->node, list);
1569			  if (!nref)
1570			    break;
1571			  tem = expand_node_name (nref->containing_node);
1572			  if (STREQ (tem, tags_up))
1573			    {
1574			      if (nref->type != menu_reference)
1575				tref = nref;
1576			      else
1577				{
1578				  free (tem);
1579				  break;
1580				}
1581			    }
1582			  free (tem);
1583			  list = nref->next;
1584			}
1585		    }
1586                  if (!nref && !tref)
1587                    {
1588                      temp_tag = find_node (tags->up);
1589                      file_line_error (temp_tag->filename, temp_tag->line_no,
1590           _("Node `%s' lacks menu item for `%s' despite being its Up target"),
1591                                  tags->up, tags->node);
1592                    }
1593                }
1594            }
1595        }
1596      tags = tags->next_ent;
1597    }
1598
1599  validate_other_references (node_references);
1600  /* We have told the user about the references which didn't exist.
1601     Now tell him about the nodes which aren't referenced. */
1602
1603  for (tags = tag_table; tags; tags = tags->next_ent)
1604    {
1605      /* If this node is a "no warn" node, do nothing. */
1606      if (tags->flags & TAG_FLAG_NO_WARN)
1607        {
1608          tags = tags->next_ent;
1609          continue;
1610        }
1611
1612      /* Special hack.  If the node in question appears to have
1613         been referenced more than REFERENCE_WARNING_LIMIT times,
1614         give a warning. */
1615      if (tags->touched > reference_warning_limit)
1616        {
1617          input_filename = tags->filename;
1618          line_number = tags->line_no;
1619          warning (_("node `%s' has been referenced %d times"),
1620                   tags->node, tags->touched);
1621        }
1622
1623      if (tags->touched == 0)
1624        {
1625          input_filename = tags->filename;
1626          line_number = tags->line_no;
1627
1628          /* Notice that the node "Top" is special, and doesn't have to
1629             be referenced.   Anchors don't have to be referenced
1630             either, you might define them for another document.  */
1631          if (strcasecmp (tags->node, "Top") != 0
1632              && !(tags->flags & TAG_FLAG_ANCHOR))
1633            warning (_("unreferenced node `%s'"), tags->node);
1634        }
1635    }
1636  input_filename = old_input_filename;
1637}
1638
1639
1640/* Splitting */
1641
1642/* Return true if the tag entry pointed to by TAGS is the last node.
1643   This means only anchors follow.  */
1644
1645static int
1646last_node_p (TAG_ENTRY *tags)
1647{
1648  int last = 1;
1649  while (tags->next_ent) {
1650    tags = tags->next_ent;
1651    if (tags->flags & TAG_FLAG_ANCHOR)
1652      ;
1653    else
1654      {
1655        last = 0;
1656        break;
1657      }
1658  }
1659
1660  return last;
1661}
1662
1663
1664static char *
1665enumerate_filename (char *pathname, char *basename, int number)
1666{
1667  /* Do we need to generate names of subfiles which don't exceed 8+3 limits? */
1668  const int dos_file_names = !HAVE_LONG_FILENAMES (pathname ? pathname : ".");
1669  unsigned name_len = strlen (basename);
1670  char *filename = xmalloc (10 + strlen (pathname) + name_len);
1671  char *base_filename = xmalloc (10 + name_len);
1672
1673  sprintf (base_filename, "%s-%d", basename, number);
1674
1675  if (dos_file_names)
1676    {
1677      char *dot = strchr (base_filename, '.');
1678      unsigned base_len = strlen (base_filename);
1679
1680      if (dot)
1681        { /* Make foobar.i1, .., foobar.i99, foobar.100, ... */
1682          dot[1] = 'i';
1683          memmove (number <= 99 ? dot + 2 : dot + 1,
1684              base_filename + name_len + 1,
1685              strlen (base_filename + name_len + 1) + 1);
1686        }
1687      else if (base_len > 8)
1688        {
1689          /* Make foobar-1, .., fooba-10, .., foob-100, ... */
1690          unsigned numlen = base_len - name_len;
1691
1692          memmove (base_filename + 8 - numlen, base_filename + name_len, numlen + 1);
1693        }
1694    }
1695
1696  sprintf (filename, "%s%s", pathname, base_filename);
1697
1698  return filename;
1699}
1700
1701/* Remove previously split files, to avoid
1702   lingering parts of shrinked documents.  */
1703void
1704clean_old_split_files (char *filename)
1705{
1706  char *root_filename = filename_part (filename);
1707  char *root_pathname = pathname_part (filename);
1708  int i;
1709
1710  /* We break as soon as we hit an inexistent file,
1711     so looping until large numbers is harmless.  */
1712  for (i = 1; i < 1000; i++)
1713    {
1714      struct stat st;
1715      char *check_file = enumerate_filename (root_pathname, root_filename, i);
1716
1717      if (stat (check_file, &st) != 0)
1718        break;
1719      else if (!S_ISDIR (st.st_mode))
1720        {
1721          /* Give feedback if requested, removing a file is important.  */
1722          if (verbose_mode)
1723            printf (_("Removing %s\n"), check_file);
1724
1725          /* Warn user that we cannot remove the file.  */
1726          if (unlink (check_file) != 0)
1727            warning (_("Can't remove file `%s': %s"), check_file, strerror (errno));
1728        }
1729
1730      free (check_file);
1731    }
1732}
1733
1734
1735/* Split large output files into a series of smaller files.  Each file
1736   is pointed to in the tag table, which then gets written out as the
1737   original file.  The new files have the same name as the original file
1738   with a "-num" attached.  SIZE is the largest number of bytes to allow
1739   in any single split file. */
1740void
1741split_file (char *filename, int size)
1742{
1743  char *root_filename, *root_pathname;
1744  char *the_file;
1745  struct stat fileinfo;
1746  long file_size;
1747  char *the_header;
1748  int header_size;
1749
1750  /* Can only do this to files with tag tables. */
1751  if (!tag_table)
1752    return;
1753
1754  if (size == 0)
1755    size = DEFAULT_SPLIT_SIZE;
1756
1757  if ((stat (filename, &fileinfo) != 0)
1758      || (((long) fileinfo.st_size) < size))
1759    return;
1760  file_size = (long) fileinfo.st_size;
1761
1762  the_file = find_and_load (filename, 0);
1763  if (!the_file)
1764    return;
1765
1766  root_filename = filename_part (filename);
1767  root_pathname = pathname_part (filename);
1768
1769  if (!root_pathname)
1770    root_pathname = xstrdup ("");
1771
1772  /* Start splitting the file.  Walk along the tag table
1773     outputting sections of the file.  When we have written
1774     all of the nodes in the tag table, make the top-level
1775     pointer file, which contains indirect pointers and
1776     tags for the nodes. */
1777  {
1778    int which_file = 1;
1779    TAG_ENTRY *tags = tag_table;
1780    char *indirect_info = NULL;
1781
1782    /* Maybe we want a Local Variables section.  */
1783    char *trailer = info_trailer ();
1784    int trailer_len = trailer ? strlen (trailer) : 0;
1785
1786    /* Remember the `header' of this file.  The first tag in the file is
1787       the bottom of the header; the top of the file is the start. */
1788    the_header = xmalloc (1 + (header_size = tags->position));
1789    memcpy (the_header, the_file, header_size);
1790
1791    while (tags)
1792      {
1793        int file_top, file_bot, limit;
1794
1795        /* Have to include the Control-_. */
1796        file_top = file_bot = tags->position;
1797        limit = file_top + size;
1798
1799        /* If the rest of this file is only one node, then
1800           that is the entire subfile. */
1801        if (last_node_p (tags))
1802          {
1803            int i = tags->position + 1;
1804            char last_char = the_file[i];
1805
1806            while (i < file_size)
1807              {
1808                if ((the_file[i] == '\037') &&
1809                    ((last_char == '\n') ||
1810                     (last_char == '\014')))
1811                  break;
1812                else
1813                  last_char = the_file[i];
1814                i++;
1815              }
1816            file_bot = i;
1817            tags = tags->next_ent;
1818            goto write_region;
1819          }
1820
1821        /* Otherwise, find the largest number of nodes that can fit in
1822           this subfile. */
1823        for (; tags; tags = tags->next_ent)
1824          {
1825            if (last_node_p (tags))
1826              {
1827                /* This entry is the last node.  Search forward for the end
1828                   of this node, and that is the end of this file. */
1829                int i = tags->position + 1;
1830                char last_char = the_file[i];
1831
1832                while (i < file_size)
1833                  {
1834                    if ((the_file[i] == '\037') &&
1835                        ((last_char == '\n') ||
1836                         (last_char == '\014')))
1837                      break;
1838                    else
1839                      last_char = the_file[i];
1840                    i++;
1841                  }
1842                file_bot = i;
1843
1844                if (file_bot < limit)
1845                  {
1846                    tags = tags->next_ent;
1847                    goto write_region;
1848                  }
1849                else
1850                  {
1851                    /* Here we want to write out everything before the last
1852                       node, and then write the last node out in a file
1853                       by itself. */
1854                    file_bot = tags->position;
1855                    goto write_region;
1856                  }
1857              }
1858
1859            /* Write region only if this was a node, not an anchor.  */
1860            if (tags->next_ent->position > limit
1861                && !(tags->flags & TAG_FLAG_ANCHOR))
1862              {
1863                if (tags->position == file_top)
1864                  tags = tags->next_ent;
1865
1866                file_bot = tags->position;
1867
1868              write_region:
1869                {
1870                  int fd;
1871                  char *split_filename = enumerate_filename (root_pathname,
1872                      root_filename, which_file);
1873                  char *split_basename = filename_part (split_filename);
1874
1875                  fd = open (split_filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
1876                  if (fd < 0
1877                      || write (fd, the_header, header_size) != header_size
1878                      || write (fd, the_file + file_top, file_bot - file_top)
1879                         != (file_bot - file_top)
1880                      || (trailer_len
1881                          && write (fd, trailer, trailer_len) != trailer_len)
1882                      || close (fd) < 0)
1883                    {
1884                      perror (split_filename);
1885                      if (fd != -1)
1886                        close (fd);
1887                      xexit (1);
1888                    }
1889
1890                  if (!indirect_info)
1891                    {
1892                      indirect_info = the_file + file_top;
1893                      sprintf (indirect_info, "\037\nIndirect:\n");
1894                      indirect_info += strlen (indirect_info);
1895                    }
1896
1897                  sprintf (indirect_info, "%s: %d\n",
1898                           split_basename, file_top);
1899
1900                  free (split_basename);
1901                  free (split_filename);
1902                  indirect_info += strlen (indirect_info);
1903                  which_file++;
1904                  break;
1905                }
1906              }
1907          }
1908      }
1909
1910    /* We have sucessfully created the subfiles.  Now write out the
1911       original again.  We must use `output_stream', or
1912       write_tag_table_indirect () won't know where to place the output. */
1913    output_stream = fopen (filename, "w");
1914    if (!output_stream)
1915      {
1916        perror (filename);
1917        xexit (1);
1918      }
1919
1920    {
1921      int distance = indirect_info - the_file;
1922      fwrite (the_file, 1, distance, output_stream);
1923
1924      /* Inhibit newlines. */
1925      paragraph_is_open = 0;
1926
1927      /* Write the indirect tag table.  */
1928      write_tag_table_indirect ();
1929
1930      /* preserve local variables in info output.  */
1931      if (trailer)
1932        {
1933          fwrite (trailer, 1, trailer_len, output_stream);
1934          free (trailer);
1935        }
1936
1937      fclose (output_stream);
1938      free (the_header);
1939      free (the_file);
1940      return;
1941    }
1942  }
1943}
1944