(root)/
texinfo-7.1/
tp/
Texinfo/
XS/
parsetexi/
source_marks.c
       1  /* Copyright 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 <string.h>
      18  
      19  #include "parser.h"
      20  #include "debug.h"
      21  #include "source_marks.h"
      22  #include "tree.h"
      23  #include "errors.h"
      24  
      25  int include_counter = 0;
      26  int setfilename_counter = 0;
      27  int delcomment_counter = 0;
      28  int defline_continuation_counter = 0;
      29  int macro_expansion_counter = 0;
      30  int linemacro_expansion_counter = 0;
      31  int value_expansion_counter = 0;
      32  int ignored_conditional_block_counter = 0;
      33  int expanded_conditional_command_counter = 0;
      34  
      35  /* it isn't much readable to use here the SM_TYPES_LIST macro defined
      36     in a header file, but the table should be allocated in files using
      37     it only if static (or in only one file if extern) */
      38  static char *source_marks_names[SM_type_expanded_conditional_command + 1] =
      39  {
      40    #define sm_type(name) [SM_type_ ## name] = #name,
      41      SM_TYPES_LIST
      42    #undef sm_type
      43  };
      44  
      45  char *
      46  source_mark_name(enum source_mark_type type)
      47  {
      48    return source_marks_names[type];
      49  }
      50  
      51  SOURCE_MARK *
      52  new_source_mark (enum source_mark_type type)
      53  {
      54    SOURCE_MARK *source_mark = malloc (sizeof (SOURCE_MARK));
      55  
      56    /* Zero all elements */
      57    memset (source_mark, 0, sizeof (*source_mark));
      58  
      59    source_mark->type = type;
      60    source_mark->counter = -1;
      61    source_mark->status = SM_status_none;
      62    return source_mark;
      63  }
      64  
      65  void
      66  add_source_mark (SOURCE_MARK *source_mark, ELEMENT *e)
      67  {
      68    SOURCE_MARK_LIST *s_mark_list = &(e->source_mark_list);
      69    if (s_mark_list->number == s_mark_list->space)
      70      {
      71        s_mark_list->space++;  s_mark_list->space *= 1.5;
      72        s_mark_list->list = realloc (s_mark_list->list,
      73                            s_mark_list->space * sizeof (SOURCE_MARK));
      74        if (!s_mark_list->list)
      75          fatal ("realloc failed");
      76      }
      77    s_mark_list->list[s_mark_list->number] = source_mark;
      78    s_mark_list->number++;
      79  }
      80  
      81  void
      82  transfer_source_marks (ELEMENT *from_e, ELEMENT *e)
      83  {
      84    SOURCE_MARK_LIST *source_mark_list = &(from_e->source_mark_list);
      85    if (source_mark_list->number)
      86      {
      87        int i;
      88        for (i = 0; i < source_mark_list->number; i++)
      89          {
      90            add_source_mark (source_mark_list->list[i], e);
      91          }
      92        source_mark_list->number = 0;
      93      }
      94  }
      95  
      96  /* ELEMENT should be the parent container. */
      97  void
      98  place_source_mark (ELEMENT *e, SOURCE_MARK *source_mark)
      99  {
     100    ELEMENT *mark_element;
     101    /* for debug string */
     102    char *add_element_string = "no-add";
     103  
     104    source_mark->position = 0;
     105    if (e->contents.number > 0)
     106      {
     107        ELEMENT *last_child = last_contents_child (e);
     108        mark_element = last_child;
     109        if (last_child->text.end > 0)
     110          source_mark->position = count_convert_u8 (last_child->text.text);
     111      }
     112    else
     113      {
     114        /* add an empty element only used for source marks */
     115        mark_element = new_element (ET_NONE);
     116        /* set empty text to have merge_text work as expected */
     117        text_append (&mark_element->text, "");
     118        add_to_element_contents (e, mark_element);
     119        add_element_string = "add";
     120      }
     121  
     122    debug_nonl ("MARK %s c: %d p: %d %s %s ", source_mark_name(source_mark->type),
     123           source_mark->counter, source_mark->position,
     124           source_mark->status == SM_status_start ? "start"
     125            : source_mark->status == SM_status_end ? "end"
     126            : "UNDEF", add_element_string);
     127    debug_print_element(mark_element, 0); debug_nonl (" ");
     128    debug_print_element(e, 0); debug ("");
     129  
     130    add_source_mark (source_mark, mark_element);
     131  }
     132  
     133  /* ELEMENT should be the parent container. */
     134  void
     135  register_source_mark (ELEMENT *e, SOURCE_MARK *source_mark)
     136  {
     137    if (source_mark->counter == -1)
     138      {
     139        if (source_mark->type == SM_type_include)
     140          {
     141            include_counter++;
     142            source_mark->counter = include_counter;
     143          }
     144        else if (source_mark->type == SM_type_setfilename)
     145          {
     146            setfilename_counter++;
     147            source_mark->counter = setfilename_counter;
     148          }
     149        else if (source_mark->type == SM_type_delcomment)
     150          {
     151            delcomment_counter++;
     152            source_mark->counter = delcomment_counter;
     153          }
     154        else if (source_mark->type == SM_type_defline_continuation)
     155          {
     156            defline_continuation_counter++;
     157            source_mark->counter = defline_continuation_counter;
     158          }
     159        else if (source_mark->type == SM_type_macro_expansion)
     160          {
     161            macro_expansion_counter++;
     162            source_mark->counter = macro_expansion_counter;
     163          }
     164        else if (source_mark->type == SM_type_linemacro_expansion)
     165          {
     166            linemacro_expansion_counter++;
     167            source_mark->counter = linemacro_expansion_counter;
     168          }
     169        else if (source_mark->type == SM_type_value_expansion)
     170          {
     171            value_expansion_counter++;
     172            source_mark->counter = value_expansion_counter;
     173          }
     174        else if (source_mark->type == SM_type_ignored_conditional_block)
     175          {
     176            ignored_conditional_block_counter++;
     177            source_mark->counter = ignored_conditional_block_counter;
     178          }
     179        else if (source_mark->type == SM_type_expanded_conditional_command)
     180          {
     181            expanded_conditional_command_counter++;
     182            source_mark->counter = expanded_conditional_command_counter;
     183          }
     184      }
     185  
     186    place_source_mark (e, source_mark);
     187  }
     188  
     189  void
     190  source_marks_reset_counters (void)
     191  {
     192    include_counter = 0;
     193    setfilename_counter = 0;
     194    delcomment_counter = 0;
     195    defline_continuation_counter = 0;
     196    macro_expansion_counter = 0;
     197    linemacro_expansion_counter = 0;
     198    value_expansion_counter = 0;
     199    ignored_conditional_block_counter = 0;
     200    expanded_conditional_command_counter = 0;
     201  }
     202  
     203  SOURCE_MARK *
     204  remove_from_source_mark_list (SOURCE_MARK_LIST *list, int where)
     205  {
     206    SOURCE_MARK *removed;
     207  
     208    if (where < 0)
     209      where = list->number + where;
     210  
     211    if (where < 0 || where > list->number)
     212      fatal ("source marks list index out of bounds");
     213  
     214    removed = list->list[where];
     215    memmove (&list->list[where], &list->list[where + 1],
     216             (list->number - (where+1)) * sizeof (SOURCE_MARK *));
     217    list->number--;
     218    return removed;
     219  }
     220  
     221  /* relocate SOURCE_MARKS source marks with position between
     222     BEGIN_POSITION and BEGIN_POSITION + LEN to be relative to BEGIN_POSITION,
     223     and move to element E.
     224     Returns BEGIN_POSITION + LEN if there were source marks.
     225  */
     226  size_t
     227  relocate_source_marks (SOURCE_MARK_LIST *source_mark_list, ELEMENT *new_e,
     228                         size_t begin_position, size_t len)
     229  {
     230    int i = 0;
     231    int j;
     232    int list_number = source_mark_list->number;
     233    int *indices_to_remove;
     234    size_t end_position;
     235  
     236    if (list_number == 0)
     237      return 0;
     238  
     239    end_position = begin_position + len;
     240  
     241    indices_to_remove = malloc (sizeof(int) * list_number);
     242    memset (indices_to_remove, 0, sizeof(int) * list_number);
     243  
     244    while (i < list_number)
     245      {
     246        SOURCE_MARK *source_mark
     247           = source_mark_list->list[i];
     248        if ((begin_position == 0 && source_mark->position == 0)
     249            || (source_mark->position > begin_position
     250                && source_mark->position <= end_position))
     251          {
     252            indices_to_remove[i] = 1;
     253            source_mark->position
     254              = source_mark->position - begin_position;
     255            add_source_mark (source_mark, new_e);
     256          }
     257        i++;
     258        if (source_mark->position > end_position)
     259          break;
     260      }
     261    /* i is past the last index with a potential source mark to remove
     262       (to be ready for the next pass in the loop above).  So remove one */
     263    for (j = i - 1; j >= 0; j--)
     264      {
     265        if (indices_to_remove[j] == 1)
     266          remove_from_source_mark_list (source_mark_list, j);
     267      }
     268  
     269    free (indices_to_remove);
     270    return end_position;
     271  }
     272