(root)/
texinfo-7.1/
tp/
Texinfo/
XS/
parsetexi/
commands.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  
      18  #include <stdlib.h>
      19  #include <string.h>
      20  
      21  #include "command_ids.h"
      22  #include "commands.h"
      23  #include "errors.h"
      24  /* for global_accept_internalvalue */
      25  #include "parser.h"
      26  
      27  #include "command_data.c"
      28  
      29  COMMAND *user_defined_command_data = 0;
      30  static size_t user_defined_number = 0;
      31  static size_t user_defined_space = 0;
      32  
      33  static int
      34  compare_command_fn (const void *a, const void *b)
      35  {
      36    const COMMAND *ca = (COMMAND *) a;
      37    const COMMAND *cb = (COMMAND *) b;
      38  
      39    return strcmp (ca->cmdname, cb->cmdname);
      40  }
      41  
      42  /* Return element number in command_data array.  Return 0 if not found. */
      43  enum command_id
      44  lookup_command (char *cmdname)
      45  {
      46    COMMAND *c;
      47    COMMAND target;
      48    int i;
      49  
      50    target.cmdname = cmdname;
      51  
      52    /* Check for user-defined commands: macros, indexes, etc. */
      53    /* Do this before looking in the built-in commands, in case the user uses 
      54       @definfoenclose or similar to override a command.
      55       If speed is a problem, then we could set a bit in the flags on the
      56       builtin command (maybe reusing CF_INFOENCLOSE) to say to look in the
      57       user commands instead. */
      58  
      59    for (i = 0; i < user_defined_number; i++)
      60      {
      61        if (!strcmp (user_defined_command_data[i].cmdname, cmdname))
      62          return ((enum command_id) i) | USER_COMMAND_BIT;
      63      }
      64  
      65    c = (COMMAND *) bsearch (&target, builtin_command_data + 1,
      66          /* number of elements */
      67          sizeof (builtin_command_data) / sizeof (builtin_command_data[0]) - 1,
      68          sizeof (builtin_command_data[0]),
      69          compare_command_fn);
      70  
      71    if (c)
      72      {
      73        enum command_id cmd;
      74        cmd = c - &builtin_command_data[0];
      75  
      76        /* txiinternalvalue is invalid if the corresponding configuration
      77         * is not set */
      78        if (cmd == CM_txiinternalvalue && !global_accept_internalvalue) {
      79          return 0;
      80        }
      81  
      82        return cmd;
      83      }
      84  
      85  
      86    return 0;
      87  }
      88  
      89  /* Add a new user-defined Texinfo command, like an index or macro command.  No 
      90     reference to NAME is retained. */
      91  enum command_id
      92  add_texinfo_command (char *name)
      93  {
      94    enum command_id existing_cmd = lookup_command (name);
      95  
      96    if (existing_cmd & USER_COMMAND_BIT)
      97      {
      98        enum command_id user_data_cmd = existing_cmd & ~USER_COMMAND_BIT;
      99        /* FIXME it is consistent with silent replacement of macro
     100           by another user-defined command to remove the information
     101           on a previously defined macro, but it may not be right, or
     102           at least there could be a warning as there is a warning when
     103           a macro is redefined. */
     104        if (user_defined_command_data[user_data_cmd].flags & CF_MACRO)
     105          {
     106            MACRO *m = lookup_macro (existing_cmd);
     107            unset_macro_record (m);
     108          }
     109        if (user_defined_command_data[user_data_cmd].flags & CF_REGISTERED)
     110          user_defined_command_data[user_data_cmd].flags = (0 & CF_REGISTERED);
     111        else
     112          user_defined_command_data[user_data_cmd].flags = 0;
     113        user_defined_command_data[user_data_cmd].data = 0;
     114        user_defined_command_data[user_data_cmd].args_number = 0;
     115        return existing_cmd;
     116      }
     117  
     118    if (user_defined_number == user_defined_space)
     119      {
     120        user_defined_command_data
     121          = realloc (user_defined_command_data,
     122                     (user_defined_space += 10) * sizeof (COMMAND));
     123        if (!user_defined_command_data)
     124          fatal ("could not realloc");
     125      }
     126  
     127    user_defined_command_data[user_defined_number].cmdname = strdup (name);
     128    user_defined_command_data[user_defined_number].flags = 0;
     129    user_defined_command_data[user_defined_number].data = 0;
     130    user_defined_command_data[user_defined_number].args_number = 0;
     131  
     132    return ((enum command_id) user_defined_number++) | USER_COMMAND_BIT;
     133  }
     134  
     135  /* Remove CMD, for @unmacro. */
     136  void
     137  remove_texinfo_command (enum command_id cmd)
     138  {
     139    cmd &= ~USER_COMMAND_BIT;
     140    /* only pretend to remove if REGISTERED, but reset */
     141    if (user_defined_command_data[cmd].flags & CF_REGISTERED)
     142      {
     143        user_defined_command_data[cmd].data = 0;
     144        user_defined_command_data[cmd].flags = (0 | CF_REGISTERED | CF_UNKNOWN);
     145        user_defined_command_data[cmd].args_number = 0;
     146      }
     147    else
     148      {
     149        /* FIXME the cmd is never reused */
     150        free (user_defined_command_data[cmd].cmdname);
     151        user_defined_command_data[cmd].cmdname = strdup ("");
     152      }
     153  }
     154  
     155  void
     156  wipe_user_commands (void)
     157  {
     158    int i;
     159    for (i = 0; i < user_defined_number; i++)
     160      free (user_defined_command_data[i].cmdname);
     161    user_defined_number = 0;
     162  }
     163  
     164  int
     165  close_preformatted_command (enum command_id cmd_id)
     166  {
     167    return cmd_id != CM_sp
     168            && command_data(cmd_id).flags & CF_close_paragraph
     169            && !(command_data(cmd_id).flags & CF_index_entry_command);
     170  }
     171  
     172  int
     173  item_line_command (enum command_id cmd_id)
     174  {
     175    return command_data(cmd_id).data == BLOCK_item_line;
     176  }