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