Sync usage with man page.
[netbsd-mini2440.git] / gnu / dist / texinfo / makeinfo / node.c
blobbfe62abe4a7e7c254953bcbabac62ba43564b84c
1 /* $NetBSD: node.c,v 1.1.1.6 2008/09/02 07:50:47 christos Exp $ */
3 /* node.c -- nodes for Texinfo.
4 Id: node.c,v 1.27 2004/12/20 23:56:07 karl Exp
6 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
7 Foundation, Inc.
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.
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.
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. */
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"
36 /* See comments in node.h. */
37 NODE_REF *node_references = NULL;
38 NODE_REF *node_node_references = NULL;
39 TAG_ENTRY *tag_table = NULL;
40 int node_number = -1;
41 int node_order = 0;
42 int current_section = 0;
43 int outstanding_node = 0;
45 /* Adding nodes, and making tags. */
47 /* Start a new tag table. */
48 void
49 init_tag_table (void)
51 while (tag_table)
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);
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). */
66 static void
67 write_tag_table_internal (int indirect_p)
69 TAG_ENTRY *node;
70 int old_indent = no_indent;
72 if (xml)
74 flush_output ();
75 return;
78 no_indent = 1;
79 filling_enabled = 0;
80 must_start_paragraph = 0;
81 close_paragraph ();
83 if (!indirect_p)
85 no_indent = 1;
86 insert ('\n');
89 add_word_args ("\037\nTag Table:\n%s", indirect_p ? "(Indirect)\n" : "");
91 /* Do not collapse -- to -, etc., in node names. */
92 in_fixed_width_font++;
94 for (node = tag_table; node; node = node->next_ent)
96 if (node->flags & TAG_FLAG_ANCHOR)
97 { /* This reference is to an anchor. */
98 execute_string ("Ref: %s", node->node);
100 else
101 { /* This reference is to a node. */
102 execute_string ("Node: %s", node->node);
104 add_word_args ("\177%d\n", node->position);
107 add_word ("\037\nEnd Tag Table\n");
109 /* Do not collapse -- to -, etc., in node names. */
110 in_fixed_width_font--;
112 flush_output ();
113 no_indent = old_indent;
116 void
117 write_tag_table (char *filename)
119 output_stream = fopen (filename, "a");
120 if (!output_stream)
122 fs_error (filename);
123 return;
126 write_tag_table_internal (0); /* Not indirect. */
128 if (fclose (output_stream) != 0)
129 fs_error (filename);
132 static void
133 write_tag_table_indirect (void)
135 write_tag_table_internal (1);
138 /* Convert "top" and friends into "Top". */
139 static void
140 normalize_node_name (char *string)
142 if (strcasecmp (string, "Top") == 0)
143 strcpy (string, "Top");
146 static char *
147 get_node_token (int expand)
149 char *string;
151 get_until_in_line (expand, ",", &string);
153 if (curchar () == ',')
154 input_text_offset++;
156 fix_whitespace (string);
158 /* Force all versions of "top" to be "Top". */
159 normalize_node_name (string);
161 return string;
164 /* Expand any macros and other directives in a node name, and
165 return the expanded name as an malloc'ed string. */
166 char *
167 expand_node_name (char *node)
169 char *result = node;
171 if (node)
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);
181 return result;
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. */
186 TAG_ENTRY *
187 find_node (char *name)
189 TAG_ENTRY *tag = tag_table;
190 char *expanded_name;
191 char n1 = name[0];
193 while (tag)
195 if (tag->node[0] == n1 && strcmp (tag->node, name) == 0)
196 return tag;
197 tag = tag->next_ent;
200 if (!expensive_validation)
201 return NULL;
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)
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))
217 char *expanded_node = expand_node_name (tag->node);
219 if (STREQ (expanded_node, expanded_name))
221 free (expanded_node);
222 break;
224 free (expanded_node);
227 free (expanded_name);
228 return tag;
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. */
234 static TAG_ENTRY *
235 find_node_by_fname (char *fname)
237 TAG_ENTRY *tag = tag_table;
238 while (tag)
240 if (tag->html_fname && FILENAME_CMP (tag->html_fname, fname) == 0)
241 return tag;
242 tag = tag->next_ent;
245 return tag;
248 /* Remember next, prev, etc. references in a @node command, where we
249 don't care about most of the entries. */
250 static void
251 remember_node_node_reference (char *node)
253 NODE_REF *temp = xmalloc (sizeof (NODE_REF));
254 int number;
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
265 node_number++;
266 temp->number = node_number;
268 node_node_references = temp;
271 /* Remember NODE and associates. */
272 static void
273 remember_node (char *node, char *prev, char *next, char *up,
274 int position, int line_no, char *fname, int flags)
276 /* Check for existence of this tag already. */
277 if (validating)
279 TAG_ENTRY *tag = find_node (node);
280 if (tag)
282 line_error (_("Node `%s' previously defined at line %d"),
283 node, tag->line_no);
284 return;
288 if (!(flags & TAG_FLAG_ANCHOR))
290 /* Make this the current node. */
291 current_node = node;
294 /* Add it to the list. */
296 int number = number_of_node (node);
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
312 node_number++;
313 new->number = node_number;
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;
323 /* Increment the order counter, and save it. */
324 node_order++;
325 new->order = node_order;
327 tag_table = new;
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);
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. */
342 void
343 remember_node_reference (char *node, int line, enum reftype type)
345 NODE_REF *temp = xmalloc (sizeof (NODE_REF));
346 int number = number_of_node (node);
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
359 node_number++;
360 temp->number = node_number;
363 node_references = temp;
366 static void
367 isolate_nodename (char *nodename)
369 int i, c;
370 int paren_seen, paren;
372 if (!nodename)
373 return;
375 canon_white (nodename);
376 paren_seen = paren = i = 0;
378 if (*nodename == '.' || !*nodename)
380 *nodename = 0;
381 return;
384 if (*nodename == '(')
386 paren++;
387 paren_seen++;
388 i++;
391 for (; (c = nodename[i]); i++)
393 if (paren)
395 if (c == '(')
396 paren++;
397 else if (c == ')')
398 paren--;
400 continue;
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;
416 nodename[i] = 0;
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 "* "
425 char *
426 glean_node_from_menu (int remember_ref, enum reftype ref_type)
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;
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;
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);
451 get_until_in_line (0, ":", &nodename);
452 if (curchar () == ':')
453 input_text_offset++;
455 if (curchar () != ':')
457 free (nodename);
458 get_until_in_line (0, "\n", &nodename);
459 isolate_nodename (nodename);
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;
472 if (remember_ref)
473 remember_node_reference (nodename, line_number, ref_type);
475 return nodename;
478 /* Set the name of the current output file. */
479 void
480 set_current_output_filename (const char *fname)
482 if (current_output_filename)
483 free (current_output_filename);
484 current_output_filename = xstrdup (fname);
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. */
492 static void
493 add_html_names (char *node)
495 char *tem = expand_node_name (node);
496 char *otem = xstrdup (tem);
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);
503 char *optr = otem;
504 int need_old = 0;
506 for (; *optr; optr++)
508 if (!cr_or_whitespace (*optr) && !URL_SAFE_CHAR (*optr))
510 need_old = 1;
511 break;
515 if (need_old)
517 add_word ("<a name=\"");
518 add_anchor_name (otem, -1); /* old anchor name conversion */
519 add_word ("\"></a>\n");
521 free (otem);
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");
530 free (tem);
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. */
540 void
541 cm_node (void)
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;
551 if (strcmp (command, "nwnode") == 0)
552 no_warn = TAG_FLAG_NO_WARN;
554 /* Get rid of unmatched brace arguments from previous commands. */
555 discard_braces ();
557 /* There also might be insertions left lying around that haven't been
558 ended yet. Do that also. */
559 discard_insertions (1);
561 if (!html && !already_outputting_pending_notes)
563 close_paragraph ();
564 output_pending_notes ();
567 new_node_pos = output_position;
569 if (macro_expansion_output_stream && !executing_string)
570 append_to_expansion_output (input_text_offset + 1);
572 /* Do not collapse -- to -, etc., in node names. */
573 in_fixed_width_font++;
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);
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))
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)
596 char *fname_for_prev_node;
598 if (current_node)
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);
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)
616 long pos1 = 0;
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)
629 flush_output ();
630 pos1 = ftell (output_stream);
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);
641 free (fname_for_prev_node);
645 filling_enabled = indented_fill = 0;
646 if (!html || (html && splitting))
647 current_footnote_number = 1;
649 if (verbose_mode)
650 printf (_("Formatting node %s...\n"), node);
652 if (macro_expansion_output_stream && !executing_string)
653 remember_itext (input_text, input_text_offset);
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;
659 no_indent = 1;
660 if (xml)
662 xml_begin_document (current_output_filename);
663 xml_begin_node ();
664 if (!docbook)
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);
673 else
674 xml_node_id = xml_id (node);
676 else if (!no_headers && !html)
678 /* Emacs Info reader cannot grok indented escape sequence. */
679 kill_self_indent (-1);
681 add_word_args ("\037\nFile: %s, Node: ", pretty_output_filename);
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;
690 /* Check for defaulting of this node's next, prev, and up fields. */
691 defaulting = (*next == 0 && *prev == 0 && *up == 0);
693 this_section = what_section (input_text + input_text_offset, NULL);
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)
702 NODE_REF *last_ref = NULL;
703 NODE_REF *ref = node_references;
705 if (this_section < 0 && !STREQ (node, "Top"))
707 char *polite_section_name = "top";
708 int i;
710 for (i = 0; section_alist[i].name; i++)
711 if (section_alist[i].level == current_section + 1)
713 polite_section_name = section_alist[i].name;
714 break;
717 line_error
718 (_("Node `%s' requires a sectioning command (e.g., %c%s)"),
719 node, COMMAND_PREFIX, polite_section_name);
721 else
723 if (strcmp (node, "Top") == 0)
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;
737 int orig_offset, orig_size;
739 int bye_offset = search_forward ("\n@bye", input_text_offset);
741 /* No matter what, make this file point back at `(dir)'. */
742 free (up);
743 up = xstrdup ("(dir)"); /* html fixxme */
745 while (1)
747 orig_offset = input_text_offset;
748 orig_size =
749 search_forward (node_search_string, orig_offset);
751 if (orig_size < 0)
752 orig_size = input_text_length;
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]))
759 char *nodename_from_menu = NULL;
761 input_text_offset =
762 search_forward ("\n* ", input_text_offset);
764 if (input_text_offset != -1)
765 nodename_from_menu = glean_node_from_menu (0, 0);
767 if (nodename_from_menu)
769 free (next);
770 next = nodename_from_menu;
771 break;
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)
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;
786 else
787 { /* No more input files to check. */
788 break;
792 input_text = saved_input_text;
793 input_text_offset = saved_input_text_offset;
794 input_text_length = saved_input_text_length;
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)
802 /* Then this is the first non-@top node seen. */
803 int level;
805 level = set_top_section_level (this_section - 1);
806 non_top_node_seen = 1;
808 while (ref)
810 if (ref->section == level)
811 ref->section = this_section - 1;
812 ref = ref->next;
815 ref = node_references;
818 while (ref)
820 if (ref->section == (this_section - 1)
821 && ref->type == menu_reference
822 && strcmp (ref->node, node) == 0)
824 char *containing_node = ref->containing_node;
826 free (up);
827 up = xstrdup (containing_node);
829 if (last_ref
830 && last_ref->type == menu_reference
831 && strcmp (last_ref->containing_node, containing_node) == 0)
833 free (next);
834 next = xstrdup (last_ref->node);
837 while (ref->section == this_section - 1
838 && ref->next
839 && ref->next->type != menu_reference)
840 ref = ref->next;
842 if (ref->next && ref->type == menu_reference
843 && strcmp (ref->next->containing_node, containing_node) == 0)
845 free (prev);
846 prev = xstrdup (ref->next->node);
848 else if (!ref->next
849 && strcasecmp (ref->containing_node, "Top") == 0)
851 free (prev);
852 prev = xstrdup (ref->containing_node);
854 break;
856 last_ref = ref;
857 ref = ref->next;
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)
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;
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);
875 output_paragraph_offset = op_orig;
876 meta_char_pos = meta_pos_orig;
879 if (!*node)
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 */
889 else
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;
899 if (html)
901 if (splitting && *node && output_stream == NULL)
903 char *dirname;
904 char filename[PATH_MAX];
906 dirname = pathname_part (current_output_filename);
907 strcpy (filename, dirname);
908 strcat (filename, fname_for_this_node);
909 free (dirname);
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)
916 output_stream = fopen (filename, "w");
917 html_output_head_p = 0; /* so that we generate HTML preamble */
918 html_output_head ();
920 else if ((tag->flags & TAG_FLAG_ANCHOR) != 0)
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 ();
938 else
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)
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);
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)
957 line_error (_("Unexpected string at end of split-HTML file `%s'"),
958 fname_for_this_node);
959 fclose (output_stream);
960 xexit (1);
962 fseek (output_stream, -epilogue_len, SEEK_END);
965 if (output_stream == NULL)
967 fs_error (filename);
968 xexit (1);
970 set_current_output_filename (filename);
973 if (!splitting && no_headers)
974 { /* cross refs need a name="#anchor" even if not writing headers */
975 add_html_names (node);
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>");
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);
990 if (next)
992 tem = expansion (next, 0);
993 add_word ((char *) _("Next:"));
994 add_word ("&nbsp;");
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);
1001 free (tem);
1003 if (prev || up)
1004 add_word (",\n");
1006 if (prev)
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);
1017 if (up)
1018 add_word (",\n");
1020 if (up)
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);
1031 /* html fixxme: we want a `top' or `contents' link here. */
1033 add_word_args ("\n%s\n", splitting ? "<hr>" : "");
1034 add_word ("</div>\n");
1037 else if (docbook)
1039 else if (xml)
1041 if (next)
1043 xml_insert_element (NODENEXT, START);
1044 execute_string ("%s", next);
1045 xml_insert_element (NODENEXT, END);
1047 if (prev)
1049 xml_insert_element (NODEPREV, START);
1050 execute_string ("%s", prev);
1051 xml_insert_element (NODEPREV, END);
1053 if (up)
1055 xml_insert_element (NODEUP, START);
1056 execute_string ("%s", up);
1057 xml_insert_element (NODEUP, END);
1060 else if (!no_headers)
1062 if (macro_expansion_output_stream)
1063 me_inhibit_expansion++;
1065 /* These strings are not translatable. */
1066 if (next)
1068 execute_string (", Next: %s", next);
1069 filling_enabled = indented_fill = 0;
1071 if (prev)
1073 execute_string (", Prev: %s", prev);
1074 filling_enabled = indented_fill = 0;
1076 if (up)
1078 execute_string (", Up: %s", up);
1079 filling_enabled = indented_fill = 0;
1081 if (macro_expansion_output_stream)
1082 me_inhibit_expansion--;
1085 close_paragraph ();
1086 no_indent = 0;
1088 /* Change the section only if there was a sectioning command. */
1089 if (this_section >= 0)
1090 current_section = this_section;
1092 if (current_node && STREQ (current_node, "Top"))
1093 top_node_seen = 1;
1095 filling_enabled = 1;
1096 in_fixed_width_font--;
1099 /* Cross-reference target at an arbitrary spot. */
1100 void
1101 cm_anchor (int arg)
1103 char *anchor;
1104 char *fname_for_anchor = NULL;
1106 if (arg == END)
1107 return;
1109 /* Parse the anchor text. */
1110 anchor = get_xref_token (1);
1112 /* Force all versions of "top" to be "Top". */
1113 normalize_node_name (anchor);
1115 /* In HTML mode, need to actually produce some output. */
1116 if (html)
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)
1122 if (!executing_string && html)
1123 html_output_head ();
1124 start_paragraph ();
1125 if (!in_fixed_width_font || in_menu || in_detailmenu)
1127 insert_string ("<p>");
1128 in_paragraph = 1;
1131 add_word ("<a name=\"");
1132 add_anchor_name (anchor, 0);
1133 add_word ("\"></a>");
1134 if (splitting)
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;
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)
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;
1164 else
1166 char *dirname, *p;
1167 char filename[PATH_MAX];
1168 FILE *anchor_stream;
1170 dirname = pathname_part (current_output_filename);
1171 strcpy (filename, dirname);
1172 strcat (filename, fname_for_anchor);
1173 free (dirname);
1175 anchor_stream = fopen (filename, "w");
1176 if (anchor_stream == NULL)
1178 fs_error (filename);
1179 xexit (1);
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)
1194 char *fn, *tem;
1196 tem = expand_node_name (current_node);
1197 fn = nodename_to_filename (tem);
1198 free (tem);
1199 fputs (fn, anchor_stream);
1200 free (fn);
1202 else
1204 char *base = filename_part (current_output_filename);
1206 fputs (base, anchor_stream);
1207 free (base);
1209 fputs ("#", anchor_stream);
1210 for (p = anchor; *p; p++)
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);
1219 fputs ("\">\n", anchor_stream);
1220 fclose (anchor_stream);
1224 else if (xml)
1226 xml_insert_element_with_attribute (ANCHOR, START, "name=\"%s\"", anchor);
1227 xml_insert_element (ANCHOR, END);
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);
1235 /* Find NODE in REF_LIST. */
1236 static NODE_REF *
1237 find_node_reference (char *node, NODE_REF *ref_list)
1239 NODE_REF *orig_ref_list = ref_list;
1240 char *expanded_node;
1242 while (ref_list)
1244 if (strcmp (node, ref_list->node) == 0)
1245 break;
1246 ref_list = ref_list->next;
1249 if (ref_list || !expensive_validation)
1250 return ref_list;
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)
1256 if (STREQ (expanded_node, ref_list->node))
1257 break;
1258 if (strchr (ref_list->node, COMMAND_PREFIX))
1260 char *expanded_ref = expand_node_name (ref_list->node);
1262 if (STREQ (expanded_node, expanded_ref))
1264 free (expanded_ref);
1265 break;
1267 free (expanded_ref);
1270 free (expanded_node);
1271 return ref_list;
1274 void
1275 free_node_references (void)
1277 NODE_REF *list, *temp;
1279 list = node_references;
1281 while (list)
1283 temp = list;
1284 free (list->node);
1285 free (list->containing_node);
1286 list = list->next;
1287 free (temp);
1289 node_references = NULL;
1292 void
1293 free_node_node_references (void)
1295 NODE_REF *list, *temp;
1297 list = node_references;
1299 while (list)
1301 temp = list;
1302 free (list->node);
1303 list = list->next;
1304 free (temp);
1306 node_node_references = NULL;
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. */
1312 number_of_node (char *node)
1314 NODE_REF *temp_ref;
1315 TAG_ENTRY *temp_node = find_node (node);
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;
1327 /* validation */
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. */
1333 static int
1334 validate (char *tag, int line, const char *label)
1336 TAG_ENTRY *result;
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;
1343 /* Otherwise, the tag must exist. */
1344 result = find_node (tag);
1346 if (!result)
1348 line_number = line;
1349 line_error (_("%s reference to nonexistent node `%s' (perhaps incorrect sectioning?)"), label, tag);
1350 return 0;
1352 result->touched++;
1353 return 1;
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. */
1359 static const char *
1360 reftype_type_string (enum reftype type)
1362 switch (type)
1364 case menu_reference:
1365 return _("Menu");
1366 case followed_reference:
1367 return _("Cross");
1368 default:
1369 return "Internal-bad-reference-type";
1373 static void
1374 validate_other_references (NODE_REF *ref_list)
1376 char *old_input_filename = input_filename;
1378 while (ref_list)
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;
1385 input_filename = old_input_filename;
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)".
1393 If the Prev is different from the Up,
1394 then the Prev node must have a Next pointing at this node.
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.
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. */
1402 void
1403 validate_file (TAG_ENTRY *tag_table)
1405 char *old_input_filename = input_filename;
1406 TAG_ENTRY *tags = tag_table;
1408 while (tags)
1410 TAG_ENTRY *temp_tag;
1411 char *tem1, *tem2;
1413 input_filename = tags->filename;
1414 line_number = tags->line_no;
1416 /* If this is a "no warn" node, don't validate it in any way. */
1417 if (tags->flags & TAG_FLAG_NO_WARN)
1419 tags = tags->next_ent;
1420 continue;
1423 /* If this node has a Next, then make sure that the Next exists. */
1424 if (tags->next)
1426 validate (tags->next, tags->line_no, _("Next"));
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))
1434 char *prev = temp_tag->prev;
1435 int you_lose = !prev || !STREQ (prev, tags->node);
1437 if (you_lose && expensive_validation)
1439 tem1 = expand_node_name (prev);
1440 tem2 = expand_node_name (tags->node);
1442 if (tem1 && tem2 && STREQ (tem1, tem2))
1443 you_lose = 0;
1444 free (tem1);
1445 free (tem2);
1447 if (you_lose)
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;
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)
1464 int valid_p = validate (tags->prev, tags->line_no, _("Prev"));
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);
1474 if (!prev_equals_up && expensive_validation)
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);
1482 if (!prev_equals_up)
1484 temp_tag = find_node (tags->prev);
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
1492 int you_lose = !temp_tag->next
1493 || !STREQ (temp_tag->next, tags->node);
1495 if (temp_tag->next && you_lose && expensive_validation)
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);
1504 if (you_lose)
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;
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)
1526 int valid_p = validate (tags->up, tags->line_no, _("Up"));
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 != '(')
1532 NODE_REF *nref;
1533 NODE_REF *tref = NULL;
1534 NODE_REF *list = node_references;
1536 for (;;)
1538 nref = find_node_reference (tags->node, list);
1539 if (!nref)
1540 break;
1542 if (strcmp (nref->containing_node, tags->up) == 0)
1544 if (nref->type != menu_reference)
1546 tref = nref;
1547 list = nref->next;
1549 else
1550 break;
1552 list = nref->next;
1555 if (!nref)
1557 if (!tref && expensive_validation)
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;
1566 list = node_references;
1568 for (;;)
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))
1576 if (nref->type != menu_reference)
1577 tref = nref;
1578 else
1580 free (tem);
1581 break;
1584 free (tem);
1585 list = nref->next;
1588 if (!nref && !tref)
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);
1598 tags = tags->next_ent;
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. */
1605 for (tags = tag_table; tags; tags = tags->next_ent)
1607 /* If this node is a "no warn" node, do nothing. */
1608 if (tags->flags & TAG_FLAG_NO_WARN)
1610 tags = tags->next_ent;
1611 continue;
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)
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);
1625 if (tags->touched == 0)
1627 input_filename = tags->filename;
1628 line_number = tags->line_no;
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);
1638 input_filename = old_input_filename;
1642 /* Splitting */
1644 /* Return true if the tag entry pointed to by TAGS is the last node.
1645 This means only anchors follow. */
1647 static int
1648 last_node_p (TAG_ENTRY *tags)
1650 int last = 1;
1651 while (tags->next_ent) {
1652 tags = tags->next_ent;
1653 if (tags->flags & TAG_FLAG_ANCHOR)
1655 else
1657 last = 0;
1658 break;
1662 return last;
1666 static char *
1667 enumerate_filename (char *pathname, char *basename, int number)
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);
1675 sprintf (base_filename, "%s-%d", basename, number);
1677 if (dos_file_names)
1679 char *dot = strchr (base_filename, '.');
1680 unsigned base_len = strlen (base_filename);
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);
1689 else if (base_len > 8)
1691 /* Make foobar-1, .., fooba-10, .., foob-100, ... */
1692 unsigned numlen = base_len - name_len;
1694 memmove (base_filename + 8 - numlen, base_filename + name_len, numlen + 1);
1698 sprintf (filename, "%s%s", pathname, base_filename);
1700 return filename;
1703 /* Remove previously split files, to avoid
1704 lingering parts of shrinked documents. */
1705 void
1706 clean_old_split_files (char *filename)
1708 char *root_filename = filename_part (filename);
1709 char *root_pathname = pathname_part (filename);
1710 int i;
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++)
1716 struct stat st;
1717 char *check_file = enumerate_filename (root_pathname, root_filename, i);
1719 if (stat (check_file, &st) != 0)
1720 break;
1721 else if (!S_ISDIR (st.st_mode))
1723 /* Give feedback if requested, removing a file is important. */
1724 if (verbose_mode)
1725 printf (_("Removing %s\n"), check_file);
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));
1732 free (check_file);
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. */
1742 void
1743 split_file (char *filename, int size)
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;
1752 /* Can only do this to files with tag tables. */
1753 if (!tag_table)
1754 return;
1756 if (size == 0)
1757 size = DEFAULT_SPLIT_SIZE;
1759 if ((stat (filename, &fileinfo) != 0)
1760 || (((long) fileinfo.st_size) < size))
1761 return;
1762 file_size = (long) fileinfo.st_size;
1764 the_file = find_and_load (filename, 0);
1765 if (!the_file)
1766 return;
1768 root_filename = filename_part (filename);
1769 root_pathname = pathname_part (filename);
1771 if (!root_pathname)
1772 root_pathname = xstrdup ("");
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. */
1780 int which_file = 1;
1781 TAG_ENTRY *tags = tag_table;
1782 char *indirect_info = NULL;
1784 /* Maybe we want a Local Variables section. */
1785 char *trailer = info_trailer ();
1786 int trailer_len = trailer ? strlen (trailer) : 0;
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);
1793 while (tags)
1795 int file_top, file_bot, limit;
1797 /* Have to include the Control-_. */
1798 file_top = file_bot = tags->position;
1799 limit = file_top + size;
1801 /* If the rest of this file is only one node, then
1802 that is the entire subfile. */
1803 if (last_node_p (tags))
1805 int i = tags->position + 1;
1806 char last_char = the_file[i];
1808 while (i < file_size)
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++;
1818 file_bot = i;
1819 tags = tags->next_ent;
1820 goto write_region;
1823 /* Otherwise, find the largest number of nodes that can fit in
1824 this subfile. */
1825 for (; tags; tags = tags->next_ent)
1827 if (last_node_p (tags))
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];
1834 while (i < file_size)
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++;
1844 file_bot = i;
1846 if (file_bot < limit)
1848 tags = tags->next_ent;
1849 goto write_region;
1851 else
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;
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))
1865 if (tags->position == file_top)
1866 tags = tags->next_ent;
1868 file_bot = tags->position;
1870 write_region:
1872 int fd;
1873 char *split_filename = enumerate_filename (root_pathname,
1874 root_filename, which_file);
1875 char *split_basename = filename_part (split_filename);
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)
1886 perror (split_filename);
1887 if (fd != -1)
1888 close (fd);
1889 xexit (1);
1892 if (!indirect_info)
1894 indirect_info = the_file + file_top;
1895 sprintf (indirect_info, "\037\nIndirect:\n");
1896 indirect_info += strlen (indirect_info);
1899 sprintf (indirect_info, "%s: %d\n",
1900 split_basename, file_top);
1902 free (split_basename);
1903 free (split_filename);
1904 indirect_info += strlen (indirect_info);
1905 which_file++;
1906 break;
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)
1918 perror (filename);
1919 xexit (1);
1923 int distance = indirect_info - the_file;
1924 fwrite (the_file, 1, distance, output_stream);
1926 /* Inhibit newlines. */
1927 paragraph_is_open = 0;
1929 /* Write the indirect tag table. */
1930 write_tag_table_indirect ();
1932 /* preserve local variables in info output. */
1933 if (trailer)
1935 fwrite (trailer, 1, trailer_len, output_stream);
1936 free (trailer);
1939 fclose (output_stream);
1940 free (the_header);
1941 free (the_file);
1942 return;