1 /* Copyright 2010-2021 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 
25 #include "command_data.c"
26 
27 COMMAND *user_defined_command_data = 0;
28 static size_t user_defined_number = 0;
29 static size_t user_defined_space = 0;
30 
31 static int
compare_command_fn(const void * a,const void * b)32 compare_command_fn (const void *a, const void *b)
33 {
34   const COMMAND *ca = (COMMAND *) a;
35   const COMMAND *cb = (COMMAND *) b;
36 
37   return strcmp (ca->cmdname, cb->cmdname);
38 }
39 
40 /* Return element number in command_data array.  Return 0 if not found. */
41 enum command_id
lookup_command(char * cmdname)42 lookup_command (char *cmdname)
43 {
44   COMMAND *c;
45   COMMAND target;
46   int i;
47 
48   target.cmdname = cmdname;
49 
50   /* Check for user-defined commands: macros, indexes, etc. */
51   /* Do this before looking in the built-in commands, in case the user uses
52      @definfoenclose or similar to override a command.
53      If speed is a problem, then we could set a bit in the flags on the
54      builtin command (maybe reusing CF_INFOENCLOSE) to say to look in the
55      user commands instead. */
56 
57   for (i = 0; i < user_defined_number; i++)
58     {
59       if (!strcmp (user_defined_command_data[i].cmdname, cmdname))
60         return ((enum command_id) i) | USER_COMMAND_BIT;
61     }
62 
63   c = (COMMAND *) bsearch (&target, builtin_command_data + 1,
64         /* number of elements */
65         sizeof (builtin_command_data) / sizeof (builtin_command_data[0]) - 1,
66         sizeof (builtin_command_data[0]),
67         compare_command_fn);
68 
69   if (c)
70     return c - &builtin_command_data[0];
71 
72 
73   return 0;
74 }
75 
76 /* Add a new user-defined Texinfo command, like an index or macro command.  No
77    reference to NAME is retained. */
78 enum command_id
add_texinfo_command(char * name)79 add_texinfo_command (char *name)
80 {
81   if (user_defined_number == user_defined_space)
82     {
83       user_defined_command_data
84         = realloc (user_defined_command_data,
85                    (user_defined_space += 10) * sizeof (COMMAND));
86       if (!user_defined_command_data)
87         fatal ("could not realloc");
88     }
89 
90   user_defined_command_data[user_defined_number].cmdname = strdup (name);
91   user_defined_command_data[user_defined_number].flags = 0;
92   user_defined_command_data[user_defined_number].data = 0;
93 
94   return ((enum command_id) user_defined_number++) | USER_COMMAND_BIT;
95 }
96 
97 /* Remove CMD, for @unmacro. */
98 void
remove_texinfo_command(enum command_id cmd)99 remove_texinfo_command (enum command_id cmd)
100 {
101   cmd &= ~USER_COMMAND_BIT;
102   free (user_defined_command_data[cmd].cmdname);
103   user_defined_command_data[cmd].cmdname = strdup ("");
104 }
105 
106 void
wipe_user_commands(void)107 wipe_user_commands (void)
108 {
109   int i;
110   for (i = 0; i < user_defined_number; i++)
111     free (user_defined_command_data[i].cmdname);
112   user_defined_number = 0;
113 }
114 
115 /* Commands that terminate a paragraph. */
116 /* We may replace this function with a macro, or represent this infomation in
117    command_data. */
118 int
close_paragraph_command(enum command_id cmd)119 close_paragraph_command (enum command_id cmd)
120 {
121   if (cmd == CM_verbatim)
122     return 1;
123 
124   /* Block commands except 'raw' and 'conditional'.  */
125 
126   if (command_data(cmd).flags & CF_block)
127     {
128       if (command_data(cmd).data == BLOCK_conditional
129           || command_data(cmd).data == BLOCK_raw)
130         return 0;
131       if (command_data(cmd).flags & CF_format_raw)
132         return 0;
133 
134       return 1;
135     }
136 
137   if (cmd == CM_titlefont
138      || cmd == CM_insertcopying
139      || cmd == CM_sp
140      || cmd == CM_verbatiminclude
141      || cmd == CM_page
142      || cmd == CM_item
143      || cmd == CM_itemx
144      || cmd == CM_tab
145      || cmd == CM_headitem
146      || cmd == CM_printindex
147      || cmd == CM_listoffloats
148      || cmd == CM_center
149      || cmd == CM_dircategory
150      || cmd == CM_contents
151      || cmd == CM_shortcontents
152      || cmd == CM_summarycontents
153      || cmd == CM_caption
154      || cmd == CM_shortcaption
155      || cmd == CM_setfilename
156      || cmd == CM_exdent)
157     return 1;
158 
159   if ((command_data(cmd).flags & CF_sectioning)
160       && !(command_data(cmd).flags & CF_root))
161     return 1;
162 
163   if ((command_data(cmd).flags & CF_def))
164     return 1;
165 
166   return 0;
167 }
168 
169 int
close_preformatted_command(enum command_id cmd_id)170 close_preformatted_command (enum command_id cmd_id)
171 {
172   return cmd_id != CM_sp && close_paragraph_command (cmd_id);
173 }
174 
175 int
item_line_command(enum command_id cmd_id)176 item_line_command (enum command_id cmd_id)
177 {
178   return cmd_id == CM_table || cmd_id == CM_ftable || cmd_id == CM_vtable;
179 }
180