summaryrefslogtreecommitdiffstats
path: root/contrib/texinfo/makeinfo/defun.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/texinfo/makeinfo/defun.c')
-rw-r--r--contrib/texinfo/makeinfo/defun.c663
1 files changed, 663 insertions, 0 deletions
diff --git a/contrib/texinfo/makeinfo/defun.c b/contrib/texinfo/makeinfo/defun.c
new file mode 100644
index 0000000..c62aba7
--- /dev/null
+++ b/contrib/texinfo/makeinfo/defun.c
@@ -0,0 +1,663 @@
+/* defun.c -- @defun and friends.
+ $Id: defun.c,v 1.11 1999/07/11 16:50:19 karl Exp $
+
+ Copyright (C) 1998, 99 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 2, 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, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "system.h"
+#include "defun.h"
+#include "insertion.h"
+#include "makeinfo.h"
+
+
+#define DEFUN_SELF_DELIMITING(c) \
+ ((c) == '(' || (c) == ')' || (c) == '[' || (c) == ']')
+
+struct token_accumulator
+{
+ unsigned int length;
+ unsigned int index;
+ char **tokens;
+};
+
+static void
+initialize_token_accumulator (accumulator)
+ struct token_accumulator *accumulator;
+{
+ accumulator->length = 0;
+ accumulator->index = 0;
+ accumulator->tokens = NULL;
+}
+
+static void
+accumulate_token (accumulator, token)
+ struct token_accumulator *accumulator;
+ char *token;
+{
+ if (accumulator->index >= accumulator->length)
+ {
+ accumulator->length += 10;
+ accumulator->tokens = xrealloc (accumulator->tokens,
+ (accumulator->length * sizeof (char *)));
+ }
+ accumulator->tokens[accumulator->index] = token;
+ accumulator->index += 1;
+}
+
+/* Given STRING_POINTER pointing at an open brace, skip forward and return a
+ pointer to just past the matching close brace. */
+static int
+scan_group_in_string (string_pointer)
+ char **string_pointer;
+{
+ char *scan_string = (*string_pointer) + 1;
+ unsigned int level = 1;
+
+ for (;;)
+ {
+ int c;
+ if (level == 0)
+ {
+ *string_pointer = scan_string;
+ return 1;
+ }
+ c = *scan_string++;
+ if (c == 0)
+ {
+ /* Tweak line_number to compensate for fact that
+ we gobbled the whole line before coming here. */
+ line_number -= 1;
+ line_error (_("Missing `}' in @def arg"));
+ line_number += 1;
+ *string_pointer = scan_string - 1;
+ return 0;
+ }
+
+ if (c == '{')
+ level += 1;
+ if (c == '}')
+ level -= 1;
+ }
+}
+
+/* Return a list of tokens from the contents of STRING.
+ Commands and brace-delimited groups count as single tokens.
+ Contiguous whitespace characters are converted to a token
+ consisting of a single space. */
+static char **
+args_from_string (string)
+ char *string;
+{
+ struct token_accumulator accumulator;
+ char *token_start, *token_end;
+ char *scan_string = string;
+
+ initialize_token_accumulator (&accumulator);
+
+ while (*scan_string)
+ { /* Replace arbitrary whitespace by a single space. */
+ if (whitespace (*scan_string))
+ {
+ scan_string += 1;
+ while (whitespace (*scan_string))
+ scan_string += 1;
+ accumulate_token ((&accumulator), (xstrdup (" ")));
+ continue;
+ }
+
+ /* Commands count as single tokens. */
+ if (*scan_string == COMMAND_PREFIX)
+ {
+ token_start = scan_string;
+ scan_string += 1;
+ if (self_delimiting (*scan_string))
+ scan_string += 1;
+ else
+ {
+ int c;
+ while (1)
+ {
+ c = *scan_string++;
+
+ if ((c == 0) || (c == '{') || (whitespace (c)))
+ {
+ scan_string -= 1;
+ break;
+ }
+ }
+
+ if (*scan_string == '{')
+ {
+ char *s = scan_string;
+ (void) scan_group_in_string (&s);
+ scan_string = s;
+ }
+ }
+ token_end = scan_string;
+ }
+
+ /* Parentheses and brackets are self-delimiting. */
+ else if (DEFUN_SELF_DELIMITING (*scan_string))
+ {
+ token_start = scan_string;
+ scan_string += 1;
+ token_end = scan_string;
+ }
+
+ /* Open brace introduces a group that is a single token. */
+ else if (*scan_string == '{')
+ {
+ char *s = scan_string;
+ int balanced = scan_group_in_string (&s);
+
+ token_start = scan_string + 1;
+ scan_string = s;
+ token_end = balanced ? (scan_string - 1) : scan_string;
+ }
+
+ /* Otherwise a token is delimited by whitespace, parentheses,
+ brackets, or braces. A token is also ended by a command. */
+ else
+ {
+ token_start = scan_string;
+
+ for (;;)
+ {
+ int c;
+
+ c = *scan_string++;
+
+ /* Do not back up if we're looking at a }; since the only
+ valid }'s are those matched with {'s, we want to give
+ an error. If we back up, we go into an infinite loop. */
+ if (!c || whitespace (c) || DEFUN_SELF_DELIMITING (c)
+ || c == '{')
+ {
+ scan_string--;
+ break;
+ }
+
+ /* If we encounter a command embedded within a token,
+ then end the token. */
+ if (c == COMMAND_PREFIX)
+ {
+ scan_string--;
+ break;
+ }
+ }
+ token_end = scan_string;
+ }
+
+ accumulate_token (&accumulator, substring (token_start, token_end));
+ }
+ accumulate_token (&accumulator, NULL);
+ return accumulator.tokens;
+}
+
+static void
+process_defun_args (defun_args, auto_var_p)
+ char **defun_args;
+ int auto_var_p;
+{
+ int pending_space = 0;
+
+ for (;;)
+ {
+ char *defun_arg = *defun_args++;
+
+ if (defun_arg == NULL)
+ break;
+
+ if (defun_arg[0] == ' ')
+ {
+ pending_space = 1;
+ continue;
+ }
+
+ if (pending_space)
+ {
+ add_char (' ');
+ pending_space = 0;
+ }
+
+ if (DEFUN_SELF_DELIMITING (defun_arg[0]))
+ add_char (defun_arg[0]);
+ else if (defun_arg[0] == '&')
+ if (html)
+ {
+ defun_arg = escape_string (xstrdup (defun_arg));
+ add_word (defun_arg);
+ free (defun_arg);
+ }
+ else
+ add_word (defun_arg);
+ else if (defun_arg[0] == COMMAND_PREFIX)
+ execute_string ("%s", defun_arg);
+ else if (auto_var_p)
+ if (html)
+ {
+ defun_arg = escape_string (xstrdup (defun_arg));
+ add_word (defun_arg);
+ free (defun_arg);
+ }
+ else
+ add_word (defun_arg);
+ else
+ add_word (defun_arg);
+ }
+}
+
+static char *
+next_nonwhite_defun_arg (arg_pointer)
+ char ***arg_pointer;
+{
+ char **scan = (*arg_pointer);
+ char *arg = (*scan++);
+
+ if ((arg != 0) && (*arg == ' '))
+ arg = *scan++;
+
+ if (arg == 0)
+ scan -= 1;
+
+ *arg_pointer = scan;
+
+ return (arg == 0) ? "" : arg;
+}
+
+
+/* This is needed also in insertion.c. */
+
+enum insertion_type
+get_base_type (type)
+ enum insertion_type type;
+{
+ enum insertion_type base_type;
+ switch (type)
+ {
+ case defivar: base_type = defcv; break;
+ case defmac: base_type = deffn; break;
+ case defmethod: base_type = defop; break;
+ case defopt: base_type = defvr; break;
+ case defspec: base_type = deffn; break;
+ case deftypefun: base_type = deftypefn; break;
+ case deftypeivar: base_type = deftypeivar; break;
+ case deftypemethod: base_type = deftypemethod; break;
+ case deftypeop: base_type = deftypeop; break;
+ case deftypevar: base_type = deftypevr; break;
+ case defun: base_type = deffn; break;
+ case defvar: base_type = defvr; break;
+ default:
+ base_type = type;
+ break;
+ }
+
+ return base_type;
+}
+
+/* Make the defun type insertion.
+ TYPE says which insertion this is.
+ X_P, if nonzero, says not to start a new insertion. */
+static void
+defun_internal (type, x_p)
+ enum insertion_type type;
+ int x_p;
+{
+ enum insertion_type base_type;
+ char **defun_args, **scan_args;
+ char *category, *defined_name, *type_name, *type_name2;
+
+ {
+ char *line;
+
+ /* The @def.. line is the only place in Texinfo where you are
+ allowed to use unquoted braces that don't delimit arguments of
+ a command or a macro; in any other place it will trigger an
+ error message from the reader loop. The special handling of
+ this case inside `args_from_string' is an extra special hack
+ which allows this. The side effect is that if we try to expand
+ the rest of the line below, the recursive reader loop will
+ signal an error if there are brace-delimited arguments on that line.
+
+ The best solution to this would be to change the syntax of
+ @def.. commands so that it doesn't violate Texinfo's own rules.
+ But it's probably too late for this now, as it will break a lot
+ of existing manuals.
+
+ Unfortunately, this means that you can't call macros, use @value, etc.
+ inside @def.. commands, sigh. */
+ get_rest_of_line (0, &line);
+ defun_args = (args_from_string (line));
+ free (line);
+ }
+
+ scan_args = defun_args;
+
+ /* Get base type and category string. */
+ base_type = get_base_type (type);
+
+ /* xx all these const strings should be determined upon
+ documentlanguage argument and NOT via gettext (kama). */
+ switch (type)
+ {
+ case defun:
+ case deftypefun:
+ category = _("Function");
+ break;
+ case defmac:
+ category = _("Macro");
+ break;
+ case defspec:
+ category = _("Special Form");
+ break;
+ case defvar:
+ case deftypevar:
+ category = _("Variable");
+ break;
+ case defopt:
+ category = _("User Option");
+ break;
+ case defivar:
+ case deftypeivar:
+ category = _("Instance Variable");
+ break;
+ case defmethod:
+ case deftypemethod:
+ category = _("Method");
+ break;
+ default:
+ category = next_nonwhite_defun_arg (&scan_args);
+ break;
+ }
+
+ /* The class name. */
+ if ((base_type == deftypefn)
+ || (base_type == deftypevr)
+ || (base_type == defcv)
+ || (base_type == defop)
+ || (base_type == deftypeivar)
+ || (base_type == deftypemethod)
+ || (base_type == deftypeop)
+ )
+ type_name = next_nonwhite_defun_arg (&scan_args);
+
+ /* The type name for typed languages. */
+ if (base_type == deftypemethod
+ || base_type == deftypeivar
+ || base_type == deftypeop
+ )
+ type_name2 = next_nonwhite_defun_arg (&scan_args);
+
+ /* The function or whatever that's actually being defined. */
+ defined_name = next_nonwhite_defun_arg (&scan_args);
+
+ /* This hack exists solely for the purposes of formatting the Texinfo
+ manual. I couldn't think of a better way. The token might be a
+ simple @@ followed immediately by more text. If this is the case,
+ then the next defun arg is part of this one, and we should
+ concatenate them. */
+ if (*scan_args && **scan_args && !whitespace (**scan_args)
+ && STREQ (defined_name, "@@"))
+ {
+ char *tem = xmalloc (3 + strlen (scan_args[0]));
+
+ sprintf (tem, "@@%s", scan_args[0]);
+
+ free (scan_args[0]);
+ scan_args[0] = tem;
+ scan_args++;
+ defined_name = tem;
+ }
+
+ if (!x_p)
+ begin_insertion (type);
+
+ /* Write the definition header line.
+ This should start at the normal indentation. */
+ current_indent -= default_indentation_increment;
+ start_paragraph ();
+
+ if (html && !x_p)
+ /* Start the definition on new paragraph. */
+ add_word ("<p>\n");
+
+ if (!html)
+ switch (base_type)
+ {
+ case deffn:
+ case defvr:
+ case deftp:
+ execute_string (" -- %s: %s", category, defined_name);
+ break;
+ case deftypefn:
+ case deftypevr:
+ execute_string (" -- %s: %s %s", category, type_name, defined_name);
+ break;
+ case defcv:
+ execute_string (" -- %s %s %s: %s", category, _("of"), type_name,
+ defined_name);
+ break;
+ case deftypeivar:
+ execute_string (" -- %s %s %s: %s %s", category, _("of"), type_name,
+ type_name2, defined_name);
+ break;
+ case defop:
+ execute_string (" -- %s %s %s: %s", category, _("on"), type_name,
+ defined_name);
+ break;
+ case deftypeop:
+ execute_string (" -- %s %s %s: %s %s", category, _("on"), type_name,
+ type_name2, defined_name);
+ break;
+ case deftypemethod:
+ execute_string (" -- %s %s %s: %s %s", category, _("on"), type_name,
+ type_name2, defined_name);
+ break;
+ }
+
+ if (html)
+ {
+ /* If this is not a @def...x version, it could only
+ be a normal version @def.... So start the table here. */
+ if (!x_p)
+ add_word ("<table width=\"100%\">\n");
+
+ /* If this is an @def...x there has to be an other @def... before
+ it, so this is only a new row within an existing table. With
+ two complete standalone tables the gap between them is too big. */
+ add_word ("<tr>\n");
+ add_word ("<td align=\"left\">");
+
+ switch (base_type)
+ {
+ case deffn:
+ case defvr:
+ case deftp:
+ /* <i> is for the following function arguments. */
+ add_word_args ("<b>%s</b><i>", defined_name);
+ break;
+ case deftypefn:
+ case deftypevr:
+ add_word_args ("%s <b>%s</b><i>", type_name, defined_name);
+ break;
+ case defcv:
+ case defop:
+ add_word_args ("<b>%s</b><i>", defined_name);
+ break;
+ case deftypemethod:
+ case deftypeop:
+ case deftypeivar:
+ add_word_args ("%s <b>%s</b><i>", type_name2, defined_name);
+ break;
+ }
+ } /* if (html)... */
+
+ current_indent += default_indentation_increment;
+
+ /* Now process the function arguments, if any. If these carry onto
+ the next line, they should be indented by two increments to
+ distinguish them from the body of the definition, which is indented
+ by one increment. */
+ current_indent += default_indentation_increment;
+
+ switch (base_type)
+ {
+ case deffn:
+ case defop:
+ process_defun_args (scan_args, 1);
+ break;
+
+ /* Through Makeinfo 1.67 we processed remaining args only for deftp,
+ deftypefn, and deftypemethod. But the libc manual, for example,
+ needs to say:
+ @deftypevar {char *} tzname[2]
+ And simply allowing the extra text seems far simpler than trying
+ to invent yet more defn commands. In any case, we should either
+ output it or give an error, not silently ignore it. */
+ default:
+ process_defun_args (scan_args, 0);
+ break;
+ }
+
+ current_indent -= default_indentation_increment;
+ close_single_paragraph ();
+
+ if (html)
+ {
+ /* xx The single words (on, off) used here, should depend on
+ documentlanguage and NOT on gettext --kama. */
+ switch (base_type)
+ {
+ case deffn:
+ case defvr:
+ case deftp:
+ case deftypefn:
+ case deftypevr:
+ add_word ("</i>"); /* close italic area for arguments */
+ /* put the rest into the second column */
+ add_word_args ("</td>\n<td align=\"right\">%s", category);
+ break;
+
+ case defcv:
+ add_word ("</td>\n<td align=\"right\">");
+ add_word_args ("%s %s %s", category, _("of"), type_name);
+ break;
+
+ case defop:
+ case deftypemethod:
+ case deftypeop:
+ add_word ("</i>");
+ add_word ("</td>\n<td align=\"right\">");
+ add_word_args ("%s %s %s", category, _("on"), type_name);
+ break;
+
+ case deftypeivar:
+ add_word ("</i>");
+ add_word ("</td>\n<td align=\"right\">");
+ add_word_args ("%s %s %s", category, _("of"), type_name);
+ break;
+ } /* switch (base_type)... */
+
+ add_word ("</td>\n"); /* close second column */
+ add_word ("</tr>\n"); /* close row */
+
+ /* This is needed because I have to know if the next line is
+ normal text or another @def..x. If text follows, create a new
+ table to get the indentation for the following text.
+
+ This construction would fail if someone uses:
+ @deffn
+ @sp 2
+ @deffnx
+ .
+ @end deffn
+ But we don't care. */
+ if (!looking_at ("@def"))
+ {
+ add_word ("</table>\n");
+ add_word ("<table width=\"95%\" align=\"center\">\n");
+ add_word ("<tr><td>\n");
+ }
+
+ } /* if (html)... */
+
+ /* Make an entry in the appropriate index. */
+ switch (base_type)
+ {
+ case deffn:
+ case deftypefn:
+ execute_string ("@findex %s\n", defined_name);
+ break;
+ case defvr:
+ case deftypevr:
+ case defcv:
+ execute_string ("@vindex %s\n", defined_name);
+ break;
+ case deftypeivar:
+ execute_string ("@vindex %s %s %s\n", defined_name, _("of"), type_name);
+ break;
+ case defop:
+ case deftypeop:
+ case deftypemethod:
+ execute_string ("@findex %s %s %s\n", defined_name, _("on"), type_name);
+ break;
+ case deftp:
+ execute_string ("@tindex %s\n", defined_name);
+ break;
+ }
+
+ /* Deallocate the token list. */
+ scan_args = defun_args;
+ while (1)
+ {
+ char * arg = (*scan_args++);
+ if (arg == NULL)
+ break;
+ free (arg);
+ }
+ free (defun_args);
+}
+
+/* Add an entry for a function, macro, special form, variable, or option.
+ If the name of the calling command ends in `x', then this is an extra
+ entry included in the body of an insertion of the same type. */
+void
+cm_defun ()
+{
+ int x_p;
+ enum insertion_type type;
+ char *temp = xstrdup (command);
+
+ x_p = (command[strlen (command) - 1] == 'x');
+
+ if (x_p)
+ temp[strlen (temp) - 1] = 0;
+
+ type = find_type_from_name (temp);
+ free (temp);
+
+ /* If we are adding to an already existing insertion, then make sure
+ that we are already in an insertion of type TYPE. */
+ if (x_p && (!insertion_level || insertion_stack->insertion != type))
+ {
+ line_error (_("Must be in `%s' insertion to use `%sx'"),
+ command, command);
+ discard_until ("\n");
+ return;
+ }
+
+ defun_internal (type, x_p);
+}
OpenPOWER on IntegriCloud