/* Copyright 2010-2023 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "command_ids.h" #include "commands.h" #include "errors.h" /* for global_accept_internalvalue */ #include "parser.h" #include "command_data.c" COMMAND *user_defined_command_data = 0; static size_t user_defined_number = 0; static size_t user_defined_space = 0; static int compare_command_fn (const void *a, const void *b) { const COMMAND *ca = (COMMAND *) a; const COMMAND *cb = (COMMAND *) b; return strcmp (ca->cmdname, cb->cmdname); } /* Return element number in command_data array. Return 0 if not found. */ enum command_id lookup_command (char *cmdname) { COMMAND *c; COMMAND target; int i; target.cmdname = cmdname; /* Check for user-defined commands: macros, indexes, etc. */ /* Do this before looking in the built-in commands, in case the user uses @definfoenclose or similar to override a command. If speed is a problem, then we could set a bit in the flags on the builtin command (maybe reusing CF_INFOENCLOSE) to say to look in the user commands instead. */ for (i = 0; i < user_defined_number; i++) { if (!strcmp (user_defined_command_data[i].cmdname, cmdname)) return ((enum command_id) i) | USER_COMMAND_BIT; } c = (COMMAND *) bsearch (&target, builtin_command_data + 1, /* number of elements */ sizeof (builtin_command_data) / sizeof (builtin_command_data[0]) - 1, sizeof (builtin_command_data[0]), compare_command_fn); if (c) { enum command_id cmd; cmd = c - &builtin_command_data[0]; /* txiinternalvalue is invalid if the corresponding configuration * is not set */ if (cmd == CM_txiinternalvalue && !global_accept_internalvalue) { return 0; } return cmd; } return 0; } /* Add a new user-defined Texinfo command, like an index or macro command. No reference to NAME is retained. */ enum command_id add_texinfo_command (char *name) { enum command_id existing_cmd = lookup_command (name); if (existing_cmd & USER_COMMAND_BIT) { enum command_id user_data_cmd = existing_cmd & ~USER_COMMAND_BIT; /* FIXME it is consistent with silent replacement of macro by another user-defined command to remove the information on a previously defined macro, but it may not be right, or at least there could be a warning as there is a warning when a macro is redefined. */ if (user_defined_command_data[user_data_cmd].flags & CF_MACRO) { MACRO *m = lookup_macro (existing_cmd); unset_macro_record (m); } if (user_defined_command_data[user_data_cmd].flags & CF_REGISTERED) user_defined_command_data[user_data_cmd].flags = (0 & CF_REGISTERED); else user_defined_command_data[user_data_cmd].flags = 0; user_defined_command_data[user_data_cmd].data = 0; user_defined_command_data[user_data_cmd].args_number = 0; return existing_cmd; } if (user_defined_number == user_defined_space) { user_defined_command_data = realloc (user_defined_command_data, (user_defined_space += 10) * sizeof (COMMAND)); if (!user_defined_command_data) fatal ("could not realloc"); } user_defined_command_data[user_defined_number].cmdname = strdup (name); user_defined_command_data[user_defined_number].flags = 0; user_defined_command_data[user_defined_number].data = 0; user_defined_command_data[user_defined_number].args_number = 0; return ((enum command_id) user_defined_number++) | USER_COMMAND_BIT; } /* Remove CMD, for @unmacro. */ void remove_texinfo_command (enum command_id cmd) { cmd &= ~USER_COMMAND_BIT; /* only pretend to remove if REGISTERED, but reset */ if (user_defined_command_data[cmd].flags & CF_REGISTERED) { user_defined_command_data[cmd].data = 0; user_defined_command_data[cmd].flags = (0 | CF_REGISTERED | CF_UNKNOWN); user_defined_command_data[cmd].args_number = 0; } else { /* FIXME the cmd is never reused */ free (user_defined_command_data[cmd].cmdname); user_defined_command_data[cmd].cmdname = strdup (""); } } void wipe_user_commands (void) { int i; for (i = 0; i < user_defined_number; i++) free (user_defined_command_data[i].cmdname); user_defined_number = 0; } int close_preformatted_command (enum command_id cmd_id) { return cmd_id != CM_sp && command_data(cmd_id).flags & CF_close_paragraph && !(command_data(cmd_id).flags & CF_index_entry_command); } int item_line_command (enum command_id cmd_id) { return command_data(cmd_id).data == BLOCK_item_line; }