1 /* Copyright 2010-2019 Free Software Foundation, Inc.
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>. */
15
16 #include <config.h>
17 #include "parser.h"
18
19 /* Return the parent if in an item_line command, @*table */
20 ELEMENT *
item_line_parent(ELEMENT * current)21 item_line_parent (ELEMENT *current)
22 {
23 if (current->type == ET_before_item && current->parent)
24 current = current->parent;
25
26 if (item_line_command (current->cmd))
27 return current;
28
29 return 0;
30 }
31
32 /* Return the parent if in a multitable. */
33 ELEMENT *
item_multitable_parent(ELEMENT * current)34 item_multitable_parent (ELEMENT *current)
35 {
36 if (current->cmd == CM_headitem
37 || current->cmd == CM_item
38 || current->cmd == CM_tab)
39 {
40 if (current->parent && current->parent->parent)
41 current = current->parent->parent;
42 }
43 else if (current->type == ET_before_item)
44 {
45 current = current->parent;
46 }
47
48 if (current->cmd == CM_multitable)
49 return current;
50
51 return 0;
52 }
53
54 /* Put the contents of a @table row in a ET_table_entry container, containing
55 a ET_table_term element and a ET_table_item element. The elements of
56 this row currently occur the end of the contents of CURRENT as immediate
57 children.
58
59 NEXT_COMMAND is the command that ends this row, usually CM_item. It is null
60 at the end of a @table. If NEXT_COMMAND is given as CM_itemx, gather a
61 ET_inter_item container instead. */
62 void
gather_previous_item(ELEMENT * current,enum command_id next_command)63 gather_previous_item (ELEMENT *current, enum command_id next_command)
64 {
65 ELEMENT *gathered;
66 enum element_type type;
67 int i, contents_count;
68
69 if (last_contents_child(current)
70 && last_contents_child(current)->type == ET_before_item)
71 {
72 if (next_command == CM_itemx)
73 line_warn ("@itemx should not begin @%s", command_name(current->cmd));
74 return;
75 }
76
77 type = next_command != CM_itemx ? ET_table_item : ET_inter_item;
78 gathered = new_element (type);
79
80 /* Starting from the end, collect everything that is not a ET_item
81 or ET_itemx and put it into the ET_table_item. */
82 contents_count = current->contents.number;
83 for (i = 0; i < contents_count; i++)
84 {
85 ELEMENT *e;
86 if (last_contents_child(current)->cmd == CM_item
87 || last_contents_child(current)->cmd == CM_itemx)
88 break;
89
90 e = pop_element_from_contents (current);
91 insert_into_contents (gathered, e, 0);
92 }
93 /* TODO: A similar algorithm is is in gather_def_item in def.c. If
94 speed is an issue then we could move all the elements at once instead
95 of calling insert_into_contents multiple times. */
96
97 if (type == ET_table_item)
98 {
99 ELEMENT *table_entry = new_element (ET_table_entry);
100 ELEMENT *table_term = new_element (ET_table_term);
101 add_to_element_contents (table_entry, table_term);
102
103 /* We previously collected elements into a ET_table_item. Now
104 do the same for ET_table_term. */
105 contents_count = current->contents.number;
106 for (i = 0; i < contents_count; i++)
107 {
108 ELEMENT *e;
109 if (last_contents_child(current)->type == ET_before_item
110 || last_contents_child(current)->type == ET_table_entry)
111 break;
112
113 e = pop_element_from_contents (current);
114 insert_into_contents (table_term, e, 0);
115 }
116
117 add_to_element_contents (current, table_entry);
118
119 if (gathered->contents.number > 0)
120 add_to_element_contents (table_entry, gathered);
121 else
122 destroy_element (gathered);
123 }
124 else /* Gathering ET_inter_item between @item and @itemx */
125 {
126 /* Text between @item and @itemx is only allowed in a few cases:
127 comments, empty lines, or index entries. */
128 if (check_no_text (gathered))
129 line_error ("@itemx must follow @item");
130
131 if (gathered->contents.number > 0)
132 add_to_element_contents (current, gathered);
133 else
134 destroy_element (gathered);
135 }
136 }
137