Back to index

tetex-bin  3.0
defun.c
Go to the documentation of this file.
00001 /* defun.c -- @defun and friends.
00002    $Id: defun.c,v 1.11 2004/04/11 17:56:46 karl Exp $
00003 
00004    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
00005    Foundation, Inc.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2, or (at your option)
00010    any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software Foundation,
00019    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00020 
00021 #include "system.h"
00022 #include "defun.h"
00023 #include "xml.h"
00024 #include "insertion.h"
00025 #include "makeinfo.h"
00026 #include "cmds.h"
00027 #include "html.h"
00028 
00029 
00030 #define DEFUN_SELF_DELIMITING(c) \
00031   ((c) == '(' || (c) == ')' || (c) == '[' || (c) == ']')
00032 
00033 struct token_accumulator
00034 {
00035   unsigned int length;
00036   unsigned int index;
00037   char **tokens;
00038 };
00039 
00040 static void
00041 initialize_token_accumulator (struct token_accumulator *accumulator)
00042 {
00043   accumulator->length = 0;
00044   accumulator->index = 0;
00045   accumulator->tokens = NULL;
00046 }
00047 
00048 static void
00049 accumulate_token (struct token_accumulator *accumulator, char *token)
00050 {
00051   if (accumulator->index >= accumulator->length)
00052     {
00053       accumulator->length += 10;
00054       accumulator->tokens = xrealloc (accumulator->tokens,
00055                                       (accumulator->length * sizeof (char *)));
00056     }
00057   accumulator->tokens[accumulator->index] = token;
00058   accumulator->index += 1;
00059 }
00060 
00061 /* Given STRING_POINTER pointing at an open brace, skip forward and return a
00062    pointer to just past the matching close brace. */
00063 static int
00064 scan_group_in_string (char **string_pointer)
00065 {
00066   char *scan_string = (*string_pointer) + 1;
00067   unsigned int level = 1;
00068   int started_command = 0;
00069 
00070   for (;;)
00071     {
00072       int c;
00073       if (level == 0)
00074         {
00075           *string_pointer = scan_string;
00076           return 1;
00077         }
00078       c = *scan_string++;
00079       if (c == 0)
00080         {
00081           /* Tweak line_number to compensate for fact that
00082              we gobbled the whole line before coming here. */
00083           line_number--;
00084           line_error (_("Missing `}' in @def arg"));
00085           line_number++;
00086           *string_pointer = scan_string - 1;
00087           return 0;
00088         }
00089 
00090       if (c == '{' && !started_command)
00091         level++;
00092       if (c == '}' && !started_command)
00093         level--;
00094 
00095       /* remember if at @.  */
00096       started_command = (c == '@' && !started_command);
00097     }
00098 }
00099 
00100 /* Return a list of tokens from the contents of STRING.
00101    Commands and brace-delimited groups count as single tokens.
00102    Contiguous whitespace characters are converted to a token
00103    consisting of a single space. */
00104 static char **
00105 args_from_string (char *string)
00106 {
00107   struct token_accumulator accumulator;
00108   char *token_start, *token_end;
00109   char *scan_string = string;
00110 
00111   initialize_token_accumulator (&accumulator);
00112 
00113   while (*scan_string)
00114     { /* Replace arbitrary whitespace by a single space. */
00115       if (whitespace (*scan_string))
00116         {
00117           scan_string += 1;
00118           while (whitespace (*scan_string))
00119             scan_string += 1;
00120           accumulate_token ((&accumulator), (xstrdup (" ")));
00121           continue;
00122         }
00123 
00124       /* Commands count as single tokens. */
00125       if (*scan_string == COMMAND_PREFIX)
00126         {
00127           token_start = scan_string;
00128           scan_string += 1;
00129           if (self_delimiting (*scan_string))
00130             scan_string += 1;
00131           else
00132             {
00133               int c;
00134               while (1)
00135                 {
00136                   c = *scan_string++;
00137 
00138                   if ((c == 0) || (c == '{') || (whitespace (c)))
00139                     {
00140                       scan_string -= 1;
00141                       break;
00142                     }
00143                 }
00144 
00145               if (*scan_string == '{')
00146                 {
00147                   char *s = scan_string;
00148                   (void) scan_group_in_string (&s);
00149                   scan_string = s;
00150                 }
00151             }
00152           token_end = scan_string;
00153         }
00154 
00155       /* Parentheses and brackets are self-delimiting. */
00156       else if (DEFUN_SELF_DELIMITING (*scan_string))
00157         {
00158           token_start = scan_string;
00159           scan_string += 1;
00160           token_end = scan_string;
00161         }
00162 
00163       /* Open brace introduces a group that is a single token. */
00164       else if (*scan_string == '{')
00165         {
00166           char *s = scan_string;
00167           int balanced = scan_group_in_string (&s);
00168 
00169           token_start = scan_string + 1;
00170           scan_string = s;
00171           token_end = balanced ? (scan_string - 1) : scan_string;
00172         }
00173 
00174       /* Make commas separate tokens so to differentiate them from
00175          parameter types in XML output. */
00176       else if (*scan_string == ',')
00177        {
00178           token_start = scan_string;
00179           scan_string += 1;
00180           token_end = scan_string;
00181        }
00182 
00183       /* Otherwise a token is delimited by whitespace, parentheses,
00184          brackets, or braces.  A token is also ended by a command. */
00185       else
00186         {
00187           token_start = scan_string;
00188 
00189           for (;;)
00190             {
00191               int c;
00192 
00193               c = *scan_string++;
00194 
00195               /* Do not back up if we're looking at a }; since the only
00196                  valid }'s are those matched with {'s, we want to give
00197                  an error.  If we back up, we go into an infinite loop.  */
00198               if (!c || whitespace (c) || DEFUN_SELF_DELIMITING (c)
00199                   || c == '{')
00200                 {
00201                   scan_string--;
00202                   break;
00203                 }
00204 
00205              /* End token if we are looking at a comma, as commas are
00206                delimiters too. */
00207              if (c == ',')
00208               {
00209                 scan_string--;
00210                 break;
00211               }
00212 
00213               /* If we encounter a command embedded within a token,
00214                  then end the token. */
00215               if (c == COMMAND_PREFIX)
00216                 {
00217                   scan_string--;
00218                   break;
00219                 }
00220             }
00221           token_end = scan_string;
00222         }
00223 
00224       accumulate_token (&accumulator, substring (token_start, token_end));
00225     }
00226   accumulate_token (&accumulator, NULL);
00227   return accumulator.tokens;
00228 }
00229 
00230 static void
00231 process_defun_args (char **defun_args, int auto_var_p)
00232 {
00233   int pending_space = 0;
00234 
00235   if (xml)
00236     {
00237       xml_process_defun_args (defun_args, auto_var_p);
00238       return;
00239     }
00240 
00241   for (;;)
00242     {
00243       char *defun_arg = *defun_args++;
00244 
00245       if (defun_arg == NULL)
00246         break;
00247 
00248       if (defun_arg[0] == ' ')
00249         {
00250           pending_space = 1;
00251           continue;
00252         }
00253 
00254       if (pending_space)
00255         {
00256           add_char (' ');
00257           pending_space = 0;
00258         }
00259 
00260       if (DEFUN_SELF_DELIMITING (defun_arg[0]))
00261         {
00262           /* Within @deffn and friends, texinfo.tex makes parentheses
00263              sans serif and brackets bold.  We use roman instead.  */
00264           if (html)
00265             insert_html_tag (START, "");
00266             
00267           add_char (defun_arg[0]);
00268           
00269           if (html)
00270             insert_html_tag (END, "");
00271         }
00272       /* else if (defun_arg[0] == '&' || defun_arg[0] == COMMAND_PREFIX) */
00273         /* execute_string ("%s", defun_arg); */
00274       /* else if (auto_var_p) */
00275         /* execute_string ("%s", defun_arg); */
00276       else
00277         execute_string ("%s", defun_arg);
00278     }
00279 }
00280 
00281 static char *
00282 next_nonwhite_defun_arg (char ***arg_pointer)
00283 {
00284   char **scan = (*arg_pointer);
00285   char *arg = (*scan++);
00286 
00287   if ((arg != 0) && (*arg == ' '))
00288     arg = *scan++;
00289 
00290   if (arg == 0)
00291     scan -= 1;
00292 
00293   *arg_pointer = scan;
00294 
00295   return (arg == 0) ? "" : arg;
00296 }
00297 
00298 
00299 /* This is needed also in insertion.c.  */
00300 
00301 enum insertion_type
00302 get_base_type (int type)
00303 {
00304   int base_type;
00305   switch (type)
00306     {
00307     case defivar:    base_type = defcv; break;
00308     case defmac:     base_type = deffn; break;
00309     case defmethod:  base_type = defop; break;
00310     case defopt:     base_type = defvr; break;
00311     case defspec:    base_type = deffn; break;
00312     case deftypecv:  base_type = deftypecv; break;
00313     case deftypefun: base_type = deftypefn; break;
00314     case deftypeivar:       base_type = deftypeivar; break;
00315     case deftypemethod:     base_type = deftypemethod; break;
00316     case deftypeop:  base_type = deftypeop; break;
00317     case deftypevar: base_type = deftypevr; break;
00318     case defun:             base_type = deffn; break;
00319     case defvar:     base_type = defvr; break;
00320     default:
00321       base_type = type;
00322       break;
00323     }
00324 
00325   return base_type;
00326 }
00327 
00328 /* Make the defun type insertion.
00329    TYPE says which insertion this is.
00330    X_P, if nonzero, says not to start a new insertion. */
00331 static void
00332 defun_internal (int type, int x_p)
00333 {
00334   int base_type;
00335   char **defun_args, **scan_args;
00336   const char *category;
00337   char *defined_name;
00338   char *type_name = NULL;
00339   char *type_name2 = NULL;
00340 
00341   {
00342     char *line;
00343 
00344     /* The @def.. line is the only place in Texinfo where you are
00345        allowed to use unquoted braces that don't delimit arguments of
00346        a command or a macro; in any other place it will trigger an
00347        error message from the reader loop.  The special handling of
00348        this case inside `args_from_string' is an extra special hack
00349        which allows this.  The side effect is that if we try to expand
00350        the rest of the line below, the recursive reader loop will
00351        signal an error if there are brace-delimited arguments on that line.
00352 
00353        The best solution to this would be to change the syntax of
00354        @def.. commands so that it doesn't violate Texinfo's own rules.
00355        But it's probably too late for this now, as it will break a lot
00356        of existing manuals.
00357 
00358        Unfortunately, this means that you can't call macros, use @value, etc.
00359        inside @def.. commands, sigh.  */
00360     get_rest_of_line (0, &line);
00361 
00362     /* Basic line continuation.  If a line ends with \s*@\s* concatanate
00363        the next line. */
00364     {
00365       char *next_line, *new_line;
00366       int i;
00367 
00368       line_continuation:
00369         i = strlen (line) - 1;
00370 
00371         if (line[i] == '@' && line[i-1] != '@')
00372           {
00373             get_rest_of_line (0, &next_line);
00374             new_line = (char *) xmalloc (i + strlen (next_line) + 2);
00375             strncpy (new_line, line, i);
00376             new_line[i] = '\0';
00377             free (line);
00378             strcat (new_line, " ");
00379             strcat (new_line, next_line);
00380             line = xstrdup (new_line);
00381             free (next_line);
00382             free (new_line);
00383 
00384             goto line_continuation;
00385           }
00386     }
00387 
00388     defun_args = (args_from_string (line));
00389     free (line);
00390   }
00391 
00392   scan_args = defun_args;
00393 
00394   /* Get base type and category string.  */
00395   base_type = get_base_type (type);
00396 
00397   /* xx all these const strings should be determined upon
00398      documentlanguage argument and NOT via gettext  (kama).  */
00399   switch (type)
00400     {
00401     case defun:
00402     case deftypefun:
00403       category = _("Function");
00404       break;
00405     case defmac:
00406       category = _("Macro");
00407       break;
00408     case defspec:
00409       category = _("Special Form");
00410       break;
00411     case defvar:
00412     case deftypevar:
00413       category = _("Variable");
00414       break;
00415     case defopt:
00416       category = _("User Option");
00417       break;
00418     case defivar:
00419     case deftypeivar:
00420       category = _("Instance Variable");
00421       break;
00422     case defmethod:
00423     case deftypemethod:
00424       category = _("Method");
00425       break;
00426     default:
00427       category = next_nonwhite_defun_arg (&scan_args);
00428       break;
00429     }
00430 
00431   /* The class name.  */
00432   if ((base_type == deftypecv)
00433       || (base_type == deftypefn)
00434       || (base_type == deftypevr)
00435       || (base_type == defcv)
00436       || (base_type == defop)
00437       || (base_type == deftypeivar)
00438       || (base_type == deftypemethod)
00439       || (base_type == deftypeop)
00440      )
00441     type_name = next_nonwhite_defun_arg (&scan_args);
00442 
00443   /* The type name for typed languages.  */
00444   if ((base_type == deftypecv)
00445       || (base_type == deftypeivar)
00446       || (base_type == deftypemethod)
00447       || (base_type == deftypeop)
00448      )
00449     type_name2 = next_nonwhite_defun_arg (&scan_args);
00450 
00451   /* The function or whatever that's actually being defined.  */
00452   defined_name = next_nonwhite_defun_arg (&scan_args);
00453 
00454   /* This hack exists solely for the purposes of formatting the Texinfo
00455      manual.  I couldn't think of a better way.  The token might be a
00456      simple @@ followed immediately by more text.  If this is the case,
00457      then the next defun arg is part of this one, and we should
00458      concatenate them. */
00459   if (*scan_args && **scan_args && !whitespace (**scan_args)
00460        && STREQ (defined_name, "@@"))
00461     {
00462       char *tem = xmalloc (3 + strlen (scan_args[0]));
00463 
00464       sprintf (tem, "@@%s", scan_args[0]);
00465 
00466       free (scan_args[0]);
00467       scan_args[0] = tem;
00468       scan_args++;
00469       defined_name = tem;
00470     }
00471 
00472   /* It's easy to write @defun foo(arg1 arg2), but a following ( is
00473      misparsed by texinfo.tex and this is next to impossible to fix.
00474      Warn about it.  */
00475   if (*scan_args && **scan_args && **scan_args == '(')
00476     warning ("`%c' follows defined name `%s' instead of whitespace",
00477              **scan_args, defined_name);
00478 
00479   if (!x_p)
00480     begin_insertion (type);
00481 
00482   /* Write the definition header line.
00483      This should start at the normal indentation.  */
00484   current_indent -= default_indentation_increment;
00485   start_paragraph ();
00486 
00487   if (!html && !xml)
00488     switch (base_type)
00489       {
00490       case deffn:
00491       case defvr:
00492       case deftp:
00493         execute_string (" --- %s: %s", category, defined_name);
00494         break;
00495       case deftypefn:
00496       case deftypevr:
00497         execute_string (" --- %s: %s %s", category, type_name, defined_name);
00498         break;
00499       case defcv:
00500         execute_string (" --- %s %s %s: %s", category, _("of"), type_name,
00501                         defined_name);
00502         break;
00503       case deftypecv:
00504       case deftypeivar:
00505         execute_string (" --- %s %s %s: %s %s", category, _("of"), type_name,
00506                         type_name2, defined_name);
00507         break;
00508       case defop:
00509         execute_string (" --- %s %s %s: %s", category, _("on"), type_name,
00510                         defined_name);
00511         break;
00512       case deftypeop:
00513         execute_string (" --- %s %s %s: %s %s", category, _("on"), type_name,
00514                         type_name2, defined_name);
00515         break;
00516       case deftypemethod:
00517         execute_string (" --- %s %s %s: %s %s", category, _("on"), type_name,
00518                         type_name2, defined_name);
00519         break;
00520       }
00521   else if (html)
00522     {
00523       /* If this is not a @def...x version, it could only
00524          be a normal version @def.... So start the table here.  */
00525       if (!x_p)
00526         insert_string ("<div class=\"defun\">\n");
00527       else
00528         rollback_empty_tag ("blockquote");
00529 
00530       /* xx The single words (on, off) used here, should depend on
00531          documentlanguage and NOT on gettext  --kama.  */
00532       switch (base_type)
00533         {
00534         case deffn:
00535         case defvr:
00536         case deftp:
00537         case deftypefn:
00538         case deftypevr:
00539           execute_string ("--- %s: ", category);
00540           break;
00541 
00542         case defcv:
00543         case deftypecv:
00544         case deftypeivar:
00545          execute_string ("--- %s %s %s: ", category, _("of"), type_name);
00546          break;
00547 
00548         case defop:
00549         case deftypemethod:
00550         case deftypeop:
00551          execute_string ("--- %s %s %s: ", category, _("on"), type_name);
00552          break;
00553        } /* switch (base_type)... */
00554 
00555       switch (base_type)
00556         {
00557         case deffn:
00558         case defvr:
00559         case deftp:
00560           /* <var> is for the following function arguments.  */
00561           insert_html_tag (START, "b");
00562           execute_string ("%s", defined_name);
00563           insert_html_tag (END, "b");
00564           insert_html_tag (START, "var");
00565           break;
00566         case deftypefn:
00567         case deftypevr:
00568           execute_string ("%s ", type_name);
00569           insert_html_tag (START, "b");
00570           execute_string ("%s", defined_name);
00571           insert_html_tag (END, "b");
00572           insert_html_tag (START, "var");
00573           break;
00574         case defcv:
00575         case defop:
00576           insert_html_tag (START, "b");
00577           execute_string ("%s", defined_name);
00578           insert_html_tag (END, "b");
00579           insert_html_tag (START, "var");
00580           break;
00581         case deftypecv:
00582         case deftypeivar:
00583         case deftypemethod:
00584         case deftypeop:
00585           execute_string ("%s ", type_name2);
00586           insert_html_tag (START, "b");
00587           execute_string ("%s", defined_name);
00588           insert_html_tag (END, "b");
00589           insert_html_tag (START, "var");
00590           break;
00591         }
00592     }
00593   else if (xml)
00594     xml_begin_def_term (base_type, category, defined_name, type_name,
00595        type_name2);
00596 
00597   current_indent += default_indentation_increment;
00598 
00599   /* Now process the function arguments, if any.  If these carry onto
00600      the next line, they should be indented by two increments to
00601      distinguish them from the body of the definition, which is indented
00602      by one increment.  */
00603   current_indent += default_indentation_increment;
00604 
00605   switch (base_type)
00606     {
00607     case deffn:
00608     case defop:
00609       process_defun_args (scan_args, 1);
00610       break;
00611 
00612       /* Through Makeinfo 1.67 we processed remaining args only for deftp,
00613          deftypefn, and deftypemethod.  But the libc manual, for example,
00614          needs to say:
00615             @deftypevar {char *} tzname[2]
00616          And simply allowing the extra text seems far simpler than trying
00617          to invent yet more defn commands.  In any case, we should either
00618          output it or give an error, not silently ignore it.  */
00619     default:
00620       process_defun_args (scan_args, 0);
00621       break;
00622     }
00623 
00624   current_indent -= default_indentation_increment;
00625   if (!html)
00626     close_single_paragraph ();
00627 
00628   /* Make an entry in the appropriate index.  (XML and
00629      Docbook already got their entries, so skip them.)  */
00630   if (!xml)
00631     switch (base_type)
00632       {
00633       case deffn:
00634       case deftypefn:
00635        execute_string ("@findex %s\n", defined_name);
00636        break;
00637       case defcv:
00638       case deftypecv:
00639       case deftypevr:
00640       case defvr:
00641        execute_string ("@vindex %s\n", defined_name);
00642        break;
00643       case deftypeivar:
00644        execute_string ("@vindex %s %s %s\n", defined_name, _("of"),
00645                         type_name);
00646        break;
00647       case defop:
00648       case deftypeop:
00649       case deftypemethod:
00650        execute_string ("@findex %s %s %s\n", defined_name, _("on"),
00651                         type_name);
00652        break;
00653       case deftp:
00654        execute_string ("@tindex %s\n", defined_name);
00655        break;
00656       }
00657 
00658   if (xml)
00659     xml_end_def_term ();
00660   else if (html)
00661     {
00662       inhibit_paragraph_indentation = 1;
00663       no_indent = 1;
00664       insert_html_tag (END, "var");
00665       insert_string ("<br>\n");
00666       /* Indent the definition a bit.  */
00667       add_html_block_elt ("<blockquote>");
00668       no_indent = 0;
00669       inhibit_paragraph_indentation = 0;
00670       paragraph_is_open = 0;
00671     }
00672 
00673   /* Deallocate the token list. */
00674   scan_args = defun_args;
00675   while (1)
00676     {
00677       char * arg = (*scan_args++);
00678       if (arg == NULL)
00679         break;
00680       free (arg);
00681     }
00682   free (defun_args);
00683 }
00684 
00685 /* Add an entry for a function, macro, special form, variable, or option.
00686    If the name of the calling command ends in `x', then this is an extra
00687    entry included in the body of an insertion of the same type. */
00688 void
00689 cm_defun (void)
00690 {
00691   int type;
00692   char *base_command = xstrdup (command);  /* command with any `x' removed */
00693   int x_p = (command[strlen (command) - 1] == 'x');
00694 
00695   if (x_p)
00696     base_command[strlen (base_command) - 1] = 0;
00697 
00698   type = find_type_from_name (base_command);
00699 
00700   /* If we are adding to an already existing insertion, then make sure
00701      that we are already in an insertion of type TYPE. */
00702   if (x_p)
00703     {
00704       INSERTION_ELT *i = insertion_stack;
00705       /* Skip over ifclear and ifset conditionals.  */
00706       while (i && (i->insertion == ifset || i->insertion == ifclear))
00707         i = i->next;
00708         
00709       if (!i || i->insertion != type)
00710         {
00711           line_error (_("Must be in `@%s' environment to use `@%s'"),
00712                       base_command, command);
00713           discard_until ("\n");
00714           return;
00715         }
00716     }
00717 
00718   defun_internal (type, x_p);
00719   free (base_command);
00720 }