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