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