(root)/
texinfo-7.1/
tp/
Texinfo/
XS/
parsetexi/
tree.c
       1  /* Copyright 2010-2023 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 <stdlib.h>
      18  #include <string.h>
      19  #include "obstack.h"
      20  
      21  #include "errors.h"
      22  #include "tree.h"
      23  #include "source_marks.h"
      24  /* for debug */
      25  #include "parser.h"
      26  
      27  static struct obstack obs_element;
      28  static int *obs_element_first = 0;
      29  
      30  /* Used with destroy_element to reuse storage, e.g. from
      31     abort_empty_line.  Reduces memory use slightly (about 5% from testing)
      32     for large manuals. */
      33  static ELEMENT *spare_element;
      34  
      35  #define obstack_chunk_alloc malloc
      36  #define obstack_chunk_free free
      37  
      38  void
      39  reset_obstacks (void)
      40  {
      41    spare_element = 0;
      42  
      43    if (obs_element_first)
      44      obstack_free (&obs_element, obs_element_first);
      45    else
      46      obstack_init (&obs_element);
      47  
      48    obs_element_first = obstack_alloc (&obs_element, sizeof (int));
      49  }
      50  
      51  static ELEMENT *alloc_element (void)
      52  {
      53    ELEMENT *e;
      54    e = (ELEMENT *) obstack_alloc (&obs_element, sizeof (ELEMENT));
      55    memset (e, 0, sizeof (ELEMENT));
      56    return e;
      57  }
      58  
      59  ELEMENT *
      60  new_element (enum element_type type)
      61  {
      62    ELEMENT *e;
      63  
      64    if (spare_element)
      65      {
      66        e = spare_element;
      67        spare_element = 0;
      68        memset (e, 0, sizeof (ELEMENT));
      69      }
      70    else
      71      {
      72        e = alloc_element ();
      73        /* alloc_element zeroes *e.  We assume null pointers have bit
      74           representation of all zeroes. */
      75      }
      76  
      77    e->type = type;
      78  
      79    return e;
      80  }
      81  
      82  void
      83  destroy_associated_info (ASSOCIATED_INFO *a)
      84  {
      85    int i;
      86  
      87    for (i = 0; i < a->info_number; i++)
      88      {
      89        switch (a->info[i].type)
      90          {
      91          case extra_string:
      92            free ((char *) a->info[i].value);
      93            break;
      94          case extra_element_oot:
      95            destroy_element_and_children ((ELEMENT *) a->info[i].value);
      96            break;
      97          case extra_contents:
      98            if (a->info[i].value)
      99              destroy_element ((ELEMENT *) a->info[i].value);
     100            break;
     101          case extra_misc_args:
     102            destroy_element_and_children ((ELEMENT *) a->info[i].value);
     103            break;
     104  
     105          default:
     106            break;
     107          }
     108      }
     109    free (a->info);
     110  }
     111  
     112  void
     113  destroy_source_mark (SOURCE_MARK *source_mark)
     114  {
     115    if (source_mark->element)
     116      destroy_element_and_children (source_mark->element);
     117    if (source_mark->line)
     118      free (source_mark->line);
     119    free (source_mark);
     120  }
     121  
     122  void
     123  destroy_source_mark_list (SOURCE_MARK_LIST *source_mark_list)
     124  {
     125    int i;
     126    for (i = 0; i < source_mark_list->number; i++)
     127      destroy_source_mark (source_mark_list->list[i]);
     128  
     129    source_mark_list->number = 0;
     130    free (source_mark_list->list);
     131    source_mark_list->space = 0;
     132  }
     133  
     134  void
     135  destroy_element (ELEMENT *e)
     136  {
     137    free (e->text.text);
     138  
     139    /* Note the pointers in these lists are not themselves freed. */
     140    free (e->contents.list);
     141    free (e->args.list);
     142  
     143    destroy_source_mark_list (&(e->source_mark_list));
     144  
     145    destroy_associated_info (&e->extra_info);
     146    destroy_associated_info (&e->info_info);
     147  
     148    spare_element = e;
     149  
     150    /* freed in reset_obstacks */
     151    /* free (e); */
     152  }
     153  
     154  /* Recursively destroy this element and all data in its descendants. */
     155  void
     156  destroy_element_and_children (ELEMENT *e)
     157  {
     158    int i;
     159  
     160    for (i = 0; i < e->contents.number; i++)
     161      destroy_element_and_children (e->contents.list[i]);
     162    for (i = 0; i < e->args.number; i++)
     163      destroy_element_and_children (e->args.list[i]);
     164  
     165    destroy_element (e);
     166  }
     167  
     168  /* Make sure there is space for at least one more element. */
     169  static void
     170  reallocate_list (ELEMENT_LIST *list)
     171  {
     172    if (list->number + 1 >= list->space)
     173      {
     174        list->space += 10;
     175        list->list = realloc (list->list, list->space * sizeof (ELEMENT *));
     176        if (!list->list)
     177          fatal ("realloc failed");
     178      }
     179  }
     180  
     181  /* Make sure there is space for at least N more elements. */
     182  static void
     183  reallocate_list_for (int n, ELEMENT_LIST *list)
     184  {
     185    if (list->number + n >= list->space)
     186      {
     187        list->space += n + 1;
     188        list->list = realloc (list->list, list->space * sizeof (ELEMENT *));
     189        if (!list->list)
     190          fatal ("realloc failed");
     191      }
     192  }
     193  
     194  void
     195  add_to_element_contents (ELEMENT *parent, ELEMENT *e)
     196  {
     197    ELEMENT_LIST *list = &parent->contents;
     198    reallocate_list (list);
     199  
     200    list->list[list->number++] = e;
     201    e->parent = parent;
     202  }
     203  
     204  /* Special purpose function for when we are only using PARENT as an
     205     array, and we don't want to overwrite E->parent. */
     206  void
     207  add_to_contents_as_array (ELEMENT *parent, ELEMENT *e)
     208  {
     209    ELEMENT_LIST *list = &parent->contents;
     210    reallocate_list (list);
     211  
     212    list->list[list->number++] = e;
     213  }
     214  
     215  void
     216  add_to_element_args (ELEMENT *parent, ELEMENT *e)
     217  {
     218    ELEMENT_LIST *list = &parent->args;
     219    reallocate_list (list);
     220  
     221    list->list[list->number++] = e;
     222    e->parent = parent;
     223  }
     224  
     225  /* Add the element E into the contents of PARENT at index WHERE. */
     226  void
     227  insert_into_contents (ELEMENT *parent, ELEMENT *e, int where)
     228  {
     229    ELEMENT_LIST *list = &parent->contents;
     230    reallocate_list (list);
     231  
     232    if (where < 0)
     233      where = list->number + where;
     234  
     235    if (where < 0 || where > list->number)
     236      fatal ("contents index out of bounds");
     237  
     238    memmove (&list->list[where + 1], &list->list[where],
     239             (list->number - where) * sizeof (ELEMENT *));
     240    list->list[where] = e;
     241    e->parent = parent;
     242    list->number++;
     243  }
     244  
     245  /* Add the element E into the arguments of PARENT at index WHERE. */
     246  void
     247  insert_into_args (ELEMENT *parent, ELEMENT *e, int where)
     248  {
     249    ELEMENT_LIST *list = &parent->args;
     250    reallocate_list (list);
     251  
     252    if (where < 0)
     253      where = list->number + where;
     254  
     255    if (where < 0 || where > list->number)
     256      fatal ("arguments index out of bounds");
     257  
     258    memmove (&list->list[where + 1], &list->list[where],
     259             (list->number - where) * sizeof (ELEMENT *));
     260    list->list[where] = e;
     261    e->parent = parent;
     262    list->number++;
     263  }
     264  
     265  /* Insert elements to the contents of TO at position WHERE from FROM
     266     from START inclusive to END exclusive.  Do not set the parent fields. */
     267  void
     268  insert_slice_into_contents (ELEMENT *to, int where, ELEMENT *from,
     269                              int start, int end)
     270  {
     271    int num = end - start;
     272    reallocate_list_for (num, &to->contents);
     273  
     274    memmove (&to->contents.list[where + num],
     275             &to->contents.list[where],
     276             (to->contents.number - where) * sizeof (ELEMENT *));
     277    memmove (&to->contents.list[where],
     278             &from->contents.list[start],
     279             num * sizeof (ELEMENT *));
     280  
     281    to->contents.number += num;
     282  }
     283  
     284  ELEMENT *
     285  remove_from_contents (ELEMENT *parent, int where)
     286  {
     287    ELEMENT_LIST *list = &parent->contents;
     288    ELEMENT *removed;
     289  
     290    if (where < 0)
     291      where = list->number + where;
     292  
     293    if (where < 0 || where > list->number)
     294      fatal ("contents index out of bounds");
     295  
     296    removed = list->list[where];
     297    memmove (&list->list[where], &list->list[where + 1],
     298             (list->number - (where+1)) * sizeof (ELEMENT *));
     299    list->number--;
     300    return removed;
     301  }
     302  
     303  /* Remove elements from START inclusive to END exclusive.  Do not
     304     free any of them. */
     305  void
     306  remove_slice_from_contents (ELEMENT *parent, int start, int end)
     307  {
     308    memmove (&parent->contents.list[start],
     309             &parent->contents.list[end],
     310             (parent->contents.number - end) * sizeof (ELEMENT *));
     311  
     312    parent->contents.number -= (end - start);
     313  }
     314  
     315  
     316  ELEMENT *
     317  pop_element_from_args (ELEMENT *parent)
     318  {
     319    ELEMENT_LIST *list = &parent->args;
     320  
     321    return list->list[--list->number];
     322  }
     323  
     324  ELEMENT *
     325  pop_element_from_contents (ELEMENT *parent)
     326  {
     327    ELEMENT_LIST *list = &parent->contents;
     328    ELEMENT *popped_element = list->list[list->number -1];
     329  
     330    list->number--;
     331  
     332    return popped_element;
     333  }
     334  
     335  ELEMENT *
     336  last_args_child (ELEMENT *current)
     337  {
     338    if (current->args.number == 0)
     339      return 0;
     340  
     341    return current->args.list[current->args.number - 1];
     342  }
     343  
     344  ELEMENT *
     345  last_contents_child (ELEMENT *current)
     346  {
     347    if (current->contents.number == 0)
     348      return 0;
     349  
     350    return current->contents.list[current->contents.number - 1];
     351  }
     352  
     353  ELEMENT *
     354  contents_child_by_index (ELEMENT *e, int index)
     355  {
     356    if (index < 0)
     357      index = e->contents.number + index;
     358  
     359    if (index < 0 || index >= e->contents.number)
     360      return 0;
     361  
     362    return e->contents.list[index];
     363  }
     364  
     365  ELEMENT *
     366  args_child_by_index (ELEMENT *e, int index)
     367  {
     368    if (index < 0)
     369      index = e->args.number + index;
     370  
     371    if (index < 0 || index >= e->args.number)
     372      return 0;
     373  
     374    return e->args.list[index];
     375  }
     376  
     377  /* should only be used if the nse->manual_content
     378     and nse->node_content are not already in the tree,
     379     in practice when the node spec was created by
     380     parse_node_manual (., 0); */
     381  void
     382  destroy_node_spec (NODE_SPEC_EXTRA *nse)
     383  {
     384    if (nse->out_of_tree_elements)
     385      {
     386        int i;
     387        for (i = 0; i < 3; i++)
     388          if (nse->out_of_tree_elements[i])
     389            destroy_element (nse->out_of_tree_elements[i]);
     390        free (nse->out_of_tree_elements);
     391      }
     392    if (nse->manual_content)
     393      destroy_element (nse->manual_content);
     394    if (nse->node_content)
     395      destroy_element (nse->node_content);
     396    free (nse);
     397  }