(root)/
texinfo-7.1/
tp/
Texinfo/
XS/
parsetexi/
convert.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 <stdio.h>
      19  #include <ctype.h>
      20  #include <string.h>
      21  
      22  #include "parser.h"
      23  #include "text.h"
      24  #include "convert.h"
      25  
      26  
      27  static void expand_cmd_args_to_texi (ELEMENT *e, TEXT *result);
      28  static void convert_to_texinfo_internal (ELEMENT *e, TEXT *result);
      29  
      30  
      31  #define ADD(x) text_append (result, x)
      32  
      33  /* Currently unused, but could be used to implement link_element_to_texi
      34     from Texinfo::Convert::Texinfo */
      35  /* Return value to be freed by caller. */
      36  char *
      37  node_extra_to_texi (NODE_SPEC_EXTRA *nse)
      38  {
      39    TEXT result;
      40  
      41    if (!nse)
      42      return "";
      43    text_init (&result);
      44  
      45    if (nse->manual_content
      46        && nse->manual_content->contents.number > 0)
      47      {
      48        text_append_n (&result, "(", 1);
      49        convert_to_texinfo_internal (nse->manual_content, &result);
      50        text_append_n (&result, ")", 1);
      51      }
      52    if (nse->node_content
      53        && nse->node_content->contents.number > 0)
      54      {
      55        convert_to_texinfo_internal (nse->node_content, &result);
      56      }
      57    return result.text;
      58  }
      59  
      60  static void
      61  expand_cmd_args_to_texi (ELEMENT *e, TEXT *result)
      62  {
      63    enum command_id cmd = e->cmd;
      64    KEY_PAIR *k, *arg_line;
      65    ELEMENT *elt, *spc_before_arg;
      66  
      67    if (cmd)
      68      {
      69        ADD("@");  ADD(command_name(cmd));
      70        elt = lookup_info_element (e, "spaces_after_cmd_before_arg");
      71        if (elt)
      72          ADD((char *)elt->text.text);
      73      }
      74  
      75    spc_before_arg = lookup_info_element (e, "spaces_before_argument");
      76  
      77    arg_line = lookup_info (e, "arg_line");
      78    if (arg_line)
      79      {
      80        char *s = 0;
      81  
      82        if (spc_before_arg)
      83          ADD((char *)spc_before_arg->text.text);
      84  
      85        s = (char *)arg_line->value;
      86        if (s)
      87          {
      88            ADD(s);
      89          }
      90      }
      91    else if (e->args.number > 0)
      92      {
      93        int braces, arg_nr, i;
      94        int with_commas = 0;
      95  
      96        braces = (e->args.list[0]->type == ET_brace_command_arg
      97                  || e->args.list[0]->type == ET_brace_command_context
      98                  || cmd == CM_value);
      99        if (braces)
     100          ADD("{");
     101  
     102        if (e->cmd == CM_verb)
     103          {
     104            k = lookup_info (e, "delimiter");
     105            ADD((char *)k->value);
     106          }
     107  
     108        if (spc_before_arg)
     109          ADD((char *)spc_before_arg->text.text);
     110  
     111        if ((command_data(cmd).flags & CF_block
     112             && ! (command_data(cmd).flags & CF_def
     113                   || cmd == CM_multitable))
     114            || cmd == CM_node
     115            || (command_data(cmd).flags & CF_brace)
     116            || (command_data(cmd).flags & CF_INFOENCLOSE))
     117          with_commas = 1;
     118  
     119        arg_nr = 0;
     120        for (i = 0; i < e->args.number; i++)
     121          {
     122            ELEMENT *arg = e->args.list[i];
     123            if (arg->type == ET_spaces_inserted
     124                || arg->type == ET_bracketed_inserted
     125                || arg->type == ET_command_as_argument_inserted)
     126              continue;
     127  
     128            if (with_commas)
     129              {
     130                if (arg_nr)
     131                  ADD(",");
     132                arg_nr++;
     133              }
     134            convert_to_texinfo_internal (arg, result);
     135          }
     136  
     137        if (e->cmd == CM_verb)
     138          {
     139            k = lookup_info (e, "delimiter");
     140            ADD((char *)k->value);
     141          }
     142  
     143        if (braces)
     144          ADD("}");
     145      }
     146    else
     147      {
     148        if (spc_before_arg)
     149          ADD((char *)spc_before_arg->text.text);
     150      }
     151  }
     152  
     153  static void
     154  convert_to_texinfo_internal (ELEMENT *e, TEXT *result)
     155  {
     156    ELEMENT *elt;
     157  
     158    if (e->type == ET_spaces_inserted
     159        || e->type == ET_bracketed_inserted
     160        || e->type == ET_command_as_argument_inserted)
     161      {}
     162    else if (e->text.end > 0)
     163      ADD(e->text.text);
     164    else
     165      {
     166        if (e->cmd
     167            || e->type == ET_def_line)
     168          {
     169            expand_cmd_args_to_texi (e, result);
     170          }
     171  
     172        if (e->type == ET_bracketed_arg || e->type == ET_bracketed_linemacro_arg)
     173          ADD("{");
     174        elt = lookup_info_element (e, "spaces_before_argument");
     175        if (elt)
     176          ADD((char *)elt->text.text);
     177        if (e->contents.number > 0)
     178          {
     179            int i;
     180            for (i = 0; i < e->contents.number; i++)
     181              convert_to_texinfo_internal (e->contents.list[i], result);
     182          }
     183  
     184        elt = lookup_info_element (e, "spaces_after_argument");
     185        if (elt)
     186          {
     187            ADD((char *)elt->text.text);
     188          }
     189  
     190        elt = lookup_info_element (e, "comment_at_end");
     191        if (elt)
     192          convert_to_texinfo_internal (elt, result);
     193  
     194        if (e->type == ET_bracketed_arg || e->type == ET_bracketed_linemacro_arg)
     195          ADD("}");
     196      }
     197  
     198    return;
     199  }
     200  #undef ADD
     201  
     202  /* Return value to be freed by caller. */
     203  char *
     204  convert_to_texinfo (ELEMENT *e)
     205  {
     206    TEXT result;
     207  
     208    if (!e)
     209      return strdup ("");
     210    text_init (&result);
     211    convert_to_texinfo_internal (e, &result);
     212    return result.text;
     213  }
     214  
     215  char *
     216  convert_contents_to_texinfo (ELEMENT *e)
     217  {
     218    ELEMENT *tmp = new_element (ET_NONE);
     219    char *result;
     220  
     221    tmp->contents = e->contents;
     222    result = convert_to_texinfo (tmp);
     223    tmp->contents.list = 0;
     224    destroy_element (tmp);
     225  
     226    return result;
     227  }
     228  
     229  /*
     230     Convert the contents of E to plain text.  Suitable for specifying a file
     231     name containing an at sign or braces, but no other commands nor element
     232     types.  Set *SUPERFLUOUS_ARG if the E contains other commands or element
     233     types. */
     234  char *
     235  convert_to_text (ELEMENT *e, int *superfluous_arg)
     236  {
     237  #define ADD(x) text_append (&result, x)
     238  
     239    TEXT result; int i;
     240  
     241    if (!e)
     242      return "";
     243    text_init (&result);
     244    for (i = 0; i < e->contents.number; i++)
     245      {
     246        ELEMENT *e1 = contents_child_by_index (e, i);
     247        if (e1->text.end > 0)
     248          ADD(e1->text.text);
     249        else if (e1->cmd == CM_AT_SIGN
     250                 || e1->cmd == CM_atchar)
     251          ADD("@");
     252        else if (e1->cmd == CM_OPEN_BRACE
     253                 || e1->cmd == CM_lbracechar)
     254          ADD("{");
     255        else if (e1->cmd == CM_CLOSE_BRACE
     256                 || e1->cmd == CM_rbracechar)
     257          ADD("}");
     258        else
     259          *superfluous_arg = 1;
     260      }
     261    return result.text;
     262  }
     263  #undef ADD
     264