(root)/
texinfo-7.1/
tp/
Texinfo/
XS/
parsetexi/
separator.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  #include <stdlib.h>
      18  #include <string.h>
      19  #include <stdio.h>
      20  
      21  #include "parser.h"
      22  #include "debug.h"
      23  #include "text.h"
      24  #include "convert.h"
      25  #include "input.h"
      26  #include "labels.h"
      27  
      28  ELEMENT *
      29  handle_open_brace (ELEMENT *current, char **line_inout)
      30  {
      31    char *line = *line_inout;
      32  
      33    if (command_flags(current) & CF_brace)
      34      {
      35        enum command_id command;
      36        ELEMENT *arg;
      37  
      38        command = current->cmd;
      39  
      40        /* if there is already content it is for spaces_after_cmd_before_arg */
      41        if (current->contents.number > 0)
      42          gather_spaces_after_cmd_before_arg (current);
      43  
      44        counter_push (&count_remaining_args, current,
      45                      command_data(current->cmd).args_number);
      46        counter_dec (&count_remaining_args);
      47  
      48        arg = new_element (ET_NONE);
      49        add_to_element_args (current, arg);
      50        current = arg;
      51        if (command_data(command).flags & CF_contain_basic_inline)
      52          push_command (&nesting_context.basic_inline_stack, command);
      53  
      54        if (command == CM_verb)
      55          {
      56            current->type = ET_brace_command_arg;
      57            /* the delimiter may be in macro expansion */
      58            if (!*line)
      59              line = new_line (current);
      60            /* Save the deliminating character in 'type'. */
      61            if (!*line || *line == '\n')
      62              {
      63                line_error ("@verb without associated character");
      64                add_info_string_dup (current->parent, "delimiter", "");
      65                current->parent->type = 0;
      66              }
      67            else
      68              {
      69                /* Count any UTF-8 continuation bytes. */
      70                int char_len = 1;
      71                char *delimiter_character;
      72                while ((line[char_len] & 0xC0) == 0x80)
      73                  char_len++;
      74                delimiter_character = strndup (line, char_len);
      75                add_info_string (current->parent, "delimiter",
      76                                 delimiter_character);
      77                line += char_len;
      78              }
      79          }
      80        else if (command_data(command).data == BRACE_context)
      81          {
      82            if (command == CM_caption || command == CM_shortcaption)
      83              {
      84  #define float floatxx
      85                ELEMENT *float;
      86                nesting_context.caption++;
      87                if (!current->parent->parent
      88                    || current->parent->parent->cmd != CM_float)
      89                  {
      90                    float = current->parent;
      91                    while (float->parent && float->cmd != CM_float)
      92                      float = float->parent;
      93                    if (float->cmd != CM_float)
      94                      {
      95                        line_error ("@%s is not meaningful outside "
      96                                    "`@float' environment",
      97                                    command_name(command));
      98                        float = 0;
      99                      }
     100                    else
     101                      line_warn ("@%s should be right below `@float'", 
     102                                 command_name(command));
     103                  }
     104                else
     105                  float = current->parent->parent;
     106                if (float)
     107                  {
     108                    if (lookup_extra (float, command_name(command)))
     109                      line_warn ("ignoring multiple @%s",
     110                                 command_name(command));
     111                    else
     112                      {
     113                        add_extra_element (current->parent, "float", float);
     114                        add_extra_element (float, command_name(command), 
     115                                               current->parent);
     116                      }
     117                  }
     118  #undef float
     119              }
     120            else if (command == CM_footnote)
     121              {
     122                nesting_context.footnote++;
     123              }
     124  
     125            /* Add to context stack. */
     126            switch (command)
     127              {
     128              case CM_footnote:
     129                push_context (ct_brace_command, command);
     130                break;
     131              case CM_caption:
     132                push_context (ct_brace_command, command);
     133                break;
     134              case CM_shortcaption:
     135                push_context (ct_brace_command, command);
     136                break;
     137              case CM_math:
     138                push_context (ct_math, command);
     139                break;
     140              default:
     141                fatal ("no context for command");
     142              }
     143  
     144            {
     145              ELEMENT *e;
     146              int n;
     147              n = strspn (line, whitespace_chars_except_newline);
     148              e = new_element (ET_internal_spaces_before_argument);
     149              text_append_n (&e->text, line, n);
     150              add_to_element_contents (current, e);
     151              add_extra_element (e, "spaces_associated_command", current->parent);
     152              line += n;
     153            }
     154            current->type = ET_brace_command_context;
     155          }
     156        else /* not context brace */
     157          {
     158            current->type = ET_brace_command_arg;
     159  
     160            /* Commands that disregard leading whitespace. */
     161            if (command_data(command).data == BRACE_arguments
     162                || command_data(command).data == BRACE_inline)
     163              {
     164                ELEMENT *e;
     165                e = new_element (ET_internal_spaces_before_argument);
     166                /* See comment in parser.c:merge_text */
     167                text_append (&e->text, "");
     168                add_to_element_contents (current, e);
     169                add_extra_element (e, "spaces_associated_command", current);
     170  
     171                if (command == CM_inlineraw)
     172                  push_context (ct_inlineraw, command);
     173              }
     174          }
     175        debug_nonl ("OPENED @%s, remaining: %d ",
     176                    command_name (current->parent->cmd),
     177                    counter_value (&count_remaining_args, current->parent) > 0 ?
     178                     counter_value (&count_remaining_args, current->parent) : 0);
     179        debug_print_element (current, 0); debug ("");
     180      }
     181    else if (current->parent && (current->parent->cmd == CM_multitable
     182                                 || current->parent->type == ET_def_line
     183                                 || current->parent->type == ET_linemacro_call))
     184      {
     185        ELEMENT *b, *e;
     186        abort_empty_line (&current, NULL);
     187        b = new_element (ET_bracketed_arg);
     188        add_to_element_contents (current, b);
     189        current = b;
     190  
     191        /* We need the line number here in case @ protects the
     192           end of the line.  */
     193        if (current->parent->parent->type == ET_def_line)
     194          current->source_info = current_source_info;
     195  
     196        e = new_element (ET_internal_spaces_before_argument);
     197        text_append (&e->text, ""); /* See comment in parser.c:merge_text */
     198        add_to_element_contents (current, e);
     199        debug ("BRACKETED in def/multitable");
     200        add_extra_element (e, "spaces_associated_command", current);
     201      }
     202    else if (current->type == ET_rawpreformatted)
     203      {
     204        debug ("LONE OPEN BRACE in rawpreformatted");
     205        current = merge_text (current, "{", 0);
     206      }
     207    /* matching braces accepted in a rawpreformatted, inline raw or
     208       math.  Note that for rawpreformatted, it can only happen
     209       within an @-command as { is simply added as seen just above.
     210     */
     211    else if (current_context() == ct_math
     212             || current_context() == ct_rawpreformatted
     213             || current_context() == ct_inlineraw)
     214      {
     215        ELEMENT *b = new_element (ET_balanced_braces);
     216        ELEMENT *open_brace = new_element (ET_NONE);
     217        abort_empty_line (&current, NULL);
     218        b->source_info = current_source_info;
     219        add_to_element_contents (current, b);
     220        current = b;
     221        text_append (&open_brace->text, "{");
     222        add_to_element_contents (current, open_brace);
     223        debug ("BALANCED BRACES in math/rawpreformatted/inlineraw");
     224      }
     225    else
     226      {
     227        line_error ("misplaced {");
     228      }
     229  
     230    *line_inout = line;
     231    return current;
     232  }
     233  
     234  /* Return 1 if an element is all whitespace.
     235     Note that this function isn't completely reliable because it
     236     doesn't look deep into the element tree.
     237   */
     238  int
     239  check_empty_expansion (ELEMENT *e)
     240  {
     241    int i;
     242    for (i = 0; i < e->contents.number; i++)
     243      {
     244        ELEMENT *f = e->contents.list[i];
     245        if (!check_space_element(f))
     246          {
     247            return 0;
     248          }
     249      }
     250    return 1;
     251  }
     252  
     253  ELEMENT *
     254  handle_close_brace (ELEMENT *current, char **line_inout)
     255  {
     256    char *line = *line_inout;
     257  
     258    debug ("CLOSE BRACE");
     259  
     260    /* For footnote and caption closing, when there is a paragraph inside.
     261       This makes the brace command the parent element. */
     262    if (current->parent && current->parent->type == ET_brace_command_context
     263        && current->type == ET_paragraph)
     264      {
     265        abort_empty_line (&current, NULL);
     266        debug ("IN BRACE_COMMAND_CONTEXT end paragraph");
     267        current = end_paragraph (current, 0, 0);
     268      }
     269  
     270    if (current->type == ET_balanced_braces)
     271      {
     272        current = merge_text (current, "}", 0);
     273        current = current->parent;
     274      }
     275    else if (current->type == ET_bracketed_arg)
     276      {
     277        abort_empty_line (&current, NULL);
     278        current = current->parent;
     279      }
     280    else if (command_flags(current->parent) & CF_brace)
     281      {
     282        enum command_id closed_command;
     283  
     284        abort_empty_line (&current, NULL);
     285  
     286        /* determine if trailing spaces are ignored */
     287        if (command_data(current->parent->cmd).data == BRACE_arguments)
     288          isolate_last_space (current);
     289  
     290        closed_command = current->parent->cmd;
     291        debug ("CLOSING(brace) @%s", command_data(closed_command).cmdname);
     292        counter_pop (&count_remaining_args);
     293  
     294        if (current->contents.number > 0
     295            && command_data(closed_command).data == BRACE_noarg)
     296          line_warn ("command @%s does not accept arguments",
     297                     command_name(closed_command));
     298  
     299        if (closed_command == CM_anchor)
     300          {
     301            current->parent->source_info = current_source_info;
     302            if (current->contents.number == 0)
     303              line_error ("empty argument in @%s",
     304                          command_name(current->parent->cmd));
     305            else
     306              {
     307                check_register_target_element_label (current, current->parent);
     308                if (nesting_context.regions_stack.top > 0)
     309                  {
     310                    add_extra_string_dup (current, "element_region",
     311                      command_name(top_command(&nesting_context.regions_stack)));
     312                  }
     313              }
     314          }
     315        else if (command_data(closed_command).flags & CF_ref)
     316          {
     317            ELEMENT *ref = current->parent;
     318            if (ref->args.number > 0)
     319              {
     320                int link_or_inforef = (closed_command == CM_link
     321                                       || closed_command == CM_inforef);
     322                if ((link_or_inforef
     323                     && (ref->args.number <= 0
     324                         || ref->args.list[0]->contents.number == 0)
     325                     && (ref->args.number <= 2
     326                         || ref->args.list[2]->contents.number == 0))
     327                    || (!link_or_inforef
     328                         && (ref->args.number <= 0
     329                             || ref->args.list[0]->contents.number == 0)
     330                         && (ref->args.number <= 3
     331                             || ref->args.list[3]->contents.number == 0)
     332                         && (ref->args.number <= 4
     333                             || ref->args.list[4]->contents.number == 0)))
     334                  {
     335                    line_warn ("command @%s missing a node or external manual "
     336                               "argument", command_name(closed_command));
     337                  }
     338                else
     339                  {
     340                    ELEMENT *arg_label = args_child_by_index (ref, 0);
     341                    NODE_SPEC_EXTRA *ref_label_info = parse_node_manual (arg_label, 1);
     342  
     343                    if (ref_label_info && (ref_label_info->manual_content
     344                                           || ref_label_info->node_content))
     345                      {
     346                        if (ref_label_info->node_content)
     347                          add_extra_contents (arg_label, "node_content",
     348                                              ref_label_info->node_content);
     349                        if (ref_label_info->manual_content)
     350                          add_extra_contents (arg_label, "manual_content",
     351                                              ref_label_info->manual_content);
     352                      }
     353                    else
     354                      {
     355                        if (ref_label_info->manual_content)
     356                          destroy_element (ref_label_info->manual_content);
     357                        if (ref_label_info->node_content)
     358                          destroy_element (ref_label_info->node_content);
     359                      }
     360                    if ((!link_or_inforef
     361                         && (ref->args.number <= 3
     362                              || (ref->args.number <= 4
     363                                  && ref->args.list[3]->contents.number == 0)
     364                              || (ref->args.list[3]->contents.number == 0
     365                                   && ref->args.list[4]->contents.number == 0))
     366                         && !ref_label_info->manual_content)
     367                        || (link_or_inforef
     368                            && (ref->args.number <= 2
     369                                || ref->args.list[2]->contents.number == 0)))
     370                      {
     371                        /* we use the @*ref command here and not the label
     372                           command to have more information for messages */
     373                        remember_internal_xref (ref);
     374                      }
     375                    free (ref_label_info);
     376                  }
     377  
     378                if (ref->args.number > 1
     379                    && ref->args.list[1]->contents.number > 0)
     380                  {
     381                    if (check_empty_expansion (ref->args.list[1]))
     382                      {
     383                        char *texi = 0;
     384                        if (ref->args.list[1])
     385                          texi = convert_contents_to_texinfo (ref->args.list[1]);
     386  
     387                        line_warn ("in @%s empty cross reference name "
     388                                   "after expansion `%s'",
     389                                   command_name(closed_command),
     390                                   ref->args.list[1] ? texi : "");
     391                        free (texi);
     392                      }
     393                  }
     394  
     395                if (!link_or_inforef
     396                    && ref->args.number > 2
     397                    && ref->args.list[2]->contents.number > 0)
     398                  {
     399                    if (check_empty_expansion (ref->args.list[2]))
     400                      {
     401                        char *texi = 0;
     402                        if (ref->args.list[2])
     403                          texi = convert_contents_to_texinfo (ref->args.list[2]);
     404  
     405                        line_warn ("in @%s empty cross reference title "
     406                                   "after expansion `%s'",
     407                                   command_name(closed_command),
     408                                   ref->args.list[2] ? texi : "");
     409                        free (texi);
     410                      }
     411                  }
     412              }
     413          }
     414        else if (closed_command == CM_image)
     415          {
     416            ELEMENT *image = current->parent;
     417            if (image->args.number == 0
     418                || image->args.list[0]->contents.number == 0)
     419              {
     420                line_error ("@image missing filename argument");
     421              }
     422            if (global_input_encoding_name)
     423              add_extra_string_dup (image, "input_encoding_name",
     424                                    global_input_encoding_name);
     425          }
     426        else if (closed_command == CM_dotless)
     427          {
     428            if (current->contents.number > 0)
     429              {
     430                char *text = current->contents.list[0]->text.text;
     431                if (!text || (strcmp (text, "i") && strcmp (text, "j")))
     432                  {
     433                    line_error ("@dotless expects `i' or `j' as argument, "
     434                                "not `%s'", text);
     435                  }
     436              }
     437          }
     438        else if ((command_data(closed_command).data == BRACE_inline)
     439                 || closed_command == CM_abbr
     440                 || closed_command == CM_acronym)
     441          {
     442            if (current->parent->cmd == CM_inlineraw)
     443              {
     444                if (ct_inlineraw != pop_context ())
     445                  fatal ("inlineraw context expected");
     446              }
     447            if (current->parent->args.number == 0
     448                || current->parent->args.list[0]->contents.number == 0)
     449              {
     450                line_warn ("@%s missing first argument",
     451                           command_name(current->parent->cmd));
     452              }
     453          }
     454        else if (closed_command == CM_errormsg)
     455          {
     456            char *arg = current->contents.list[0]->text.text;
     457            if (arg)
     458              line_error (arg);
     459          }
     460        else if (closed_command == CM_U)
     461          {
     462            if (current->contents.number == 0)
     463              {
     464                line_warn ("no argument specified for @U");
     465              }
     466            else
     467              {
     468                char *arg = current->contents.list[0]->text.text;
     469                int n = strspn (arg, "0123456789ABCDEFabcdef");
     470                if (arg[n])
     471                  {
     472                    line_error ("non-hex digits in argument for @U: %s", arg);
     473                  }
     474                else if (n < 4)
     475                  {
     476                    line_warn
     477                      ("fewer than four hex digits in argument for @U: %s", arg);
     478                  }
     479                else
     480                  {
     481                    unsigned long int val;
     482                    int ret = sscanf (arg, "%lx", &val);
     483                    if (ret != 1)
     484                      {
     485                        debug ("hex sscanf failed %s", arg);
     486                        /* unknown error.  possibly argument is too large
     487                           for an int. */
     488                      }
     489                    if (ret != 1 || val > 0x10FFFF)
     490                      {
     491                        line_error
     492                         ("argument for @U exceeds Unicode maximum 0x10FFFF: %s",
     493                          arg);
     494                      }
     495                  }
     496  
     497              }
     498          }
     499        else if (parent_of_command_as_argument (current->parent->parent)
     500                 && current->contents.number == 0)
     501          {
     502            register_command_as_argument (current->parent);
     503          }
     504        else if (current->parent->cmd == CM_sortas
     505                 || current->parent->cmd == CM_seeentry
     506                 || current->parent->cmd == CM_seealso)
     507          {
     508            ELEMENT *index_elt;
     509            if (current->parent->parent
     510                && current->parent->parent->parent
     511                && ((command_flags(current->parent->parent->parent)
     512                      & CF_index_entry_command)
     513                    || current->parent->parent->parent->cmd == CM_subentry))
     514              {
     515                index_elt = current->parent->parent->parent;
     516                if (current->parent->cmd == CM_sortas)
     517                  {
     518                    int superfluous_arg;
     519                    char *arg = convert_to_text (current, &superfluous_arg);
     520                    if (arg && *arg)
     521                      {
     522                        add_extra_string (index_elt,
     523                                          command_name(current->parent->cmd),
     524                                          arg);
     525                      }
     526                  }
     527                else
     528                  {
     529                    add_extra_element (index_elt,
     530                                       command_name(current->parent->cmd),
     531                                       current->parent);
     532                  }
     533              }
     534          }
     535        register_global_command (current->parent);
     536  
     537        if (current->parent->cmd == CM_anchor
     538            || current->parent->cmd == CM_hyphenation
     539            || current->parent->cmd == CM_caption
     540            || current->parent->cmd == CM_shortcaption
     541            || current->parent->cmd == CM_sortas
     542            || current->parent->cmd == CM_seeentry
     543            || current->parent->cmd == CM_seealso)
     544          {
     545            ELEMENT *e;
     546            e = new_element (ET_spaces_after_close_brace);
     547            text_append (&e->text, "");
     548            add_to_element_contents (current->parent->parent, e);
     549          }
     550  
     551        current = close_brace_command (current->parent, 0, 0, 0);
     552  
     553        if (close_preformatted_command(closed_command))
     554          current = begin_preformatted (current);
     555      } /* CF_brace */
     556    else if (current->type == ET_rawpreformatted)
     557      {
     558        /* lone right braces are accepted in a rawpreformatted */
     559        current = merge_text (current, "}", 0);
     560      }
     561    else
     562      {
     563        line_error ("misplaced }");
     564      }
     565  
     566    *line_inout = line;
     567    return current;
     568  }
     569  
     570  
     571  /* Handle a comma separating arguments to a Texinfo command. */
     572  ELEMENT *
     573  handle_comma (ELEMENT *current, char **line_inout)
     574  {
     575    char *line = *line_inout;
     576    enum element_type type;
     577    ELEMENT *new_arg, *e;
     578  
     579    abort_empty_line (&current, NULL);
     580    isolate_last_space (current);
     581  
     582    type = current->type;
     583    current = current->parent;
     584  
     585    if (command_data(current->cmd).data == BRACE_inline)
     586      {
     587        KEY_PAIR *k;
     588        int expandp = 0;
     589        k = lookup_extra (current, "format");
     590        if (!k)
     591          {
     592            ELEMENT *arg = 0;
     593            char *inline_type = 0;
     594            if (current->args.number > 0
     595                && current->args.list[0]->contents.number > 0
     596                && (arg = current->args.list[0]->contents.list[0]))
     597              {
     598                if (arg->text.end > 0)
     599                  inline_type = arg->text.text;
     600              }
     601  
     602            if (!inline_type)
     603              {
     604                /* Condition is missing */
     605                debug ("INLINE COND MISSING");
     606                add_extra_string (current, "format", 0);
     607              }
     608            else
     609              {
     610                debug ("INLINE: %s", inline_type);
     611                if (current->cmd == CM_inlineraw
     612                    || current->cmd == CM_inlinefmt
     613                    || current->cmd == CM_inlinefmtifelse)
     614                  {
     615                    if (format_expanded_p (inline_type))
     616                      {
     617                        expandp = 1;
     618                        add_extra_integer (current, "expand_index", 1);
     619                      }
     620                    else
     621                      expandp = 0;
     622                  }
     623                else if (current->cmd == CM_inlineifset
     624                         || current->cmd == CM_inlineifclear)
     625                  {
     626                    expandp = 0;
     627                    if (fetch_value (inline_type))
     628                      expandp = 1;
     629                    if (current->cmd == CM_inlineifclear)
     630                      expandp = !expandp;
     631                    if (expandp)
     632                      add_extra_integer (current, "expand_index", 1);
     633                  }
     634                else
     635                  expandp = 0;
     636  
     637                add_extra_string_dup (current, "format", inline_type);
     638              }
     639  
     640            /* Skip first argument for a false @inlinefmtifelse */
     641            if (!expandp && current->cmd == CM_inlinefmtifelse)
     642              {
     643                ELEMENT *e;
     644                ELEMENT *arg;
     645                int brace_count = 1;
     646  
     647                add_extra_integer (current, "expand_index", 2);
     648  
     649                e = new_element (ET_elided_brace_command_arg);
     650                add_to_element_args (current, e);
     651                arg = new_element (ET_raw);
     652                text_append (&arg->text, "");
     653                add_to_element_contents (e, arg);
     654  
     655                /* Scan forward to get the next argument. */
     656                while (brace_count > 0)
     657                  {
     658                    static char *alloc_line;
     659                    size_t non_separator_len = strcspn (line, "{},");
     660                    if (non_separator_len > 0)
     661                      text_append_n (&arg->text, line, non_separator_len);
     662                    line += non_separator_len;
     663                    switch (*line)
     664                      {
     665                      case ',':
     666                        if (brace_count == 1)
     667                          {
     668                            line++;
     669                            goto inlinefmtifelse_done;
     670                          }
     671                        text_append_n (&arg->text, line, 1);
     672                        break;
     673                      case '{':
     674                        brace_count++;
     675                        text_append_n (&arg->text, line, 1);
     676                        break;
     677                      case '}':
     678                        brace_count--;
     679                        if (brace_count > 0)
     680                          text_append_n (&arg->text, line, 1);
     681                        break;
     682                      default:
     683                        /* at the end of line */
     684                        free (alloc_line);
     685                        line = alloc_line = next_text (e);
     686                        if (!line)
     687                          goto funexit;
     688                        continue;
     689                      }
     690                    line++;
     691                  }
     692              inlinefmtifelse_done:
     693                /* Second argument is missing. */
     694                if (brace_count == 0)
     695                  {
     696                    current = last_args_child (current);
     697                    line--; /* on '}' */
     698                    goto funexit;
     699                  }
     700                else
     701                  counter_dec (&count_remaining_args);
     702                expandp = 1;
     703              }
     704          }
     705        else if (current->cmd == CM_inlinefmtifelse)
     706          {
     707            /* Second part of @inlinefmtifelse when condition is true.  Discard
     708               second argument. */
     709            expandp = 0;
     710          }
     711  
     712        /* If this command is not being expanded, add an elided argument, and
     713           scan forward to the closing brace. */
     714        if (!expandp)
     715          {
     716            static char *alloc_line;
     717            ELEMENT *e;
     718            ELEMENT *arg;
     719            int brace_count = 1;
     720  
     721            e = new_element (ET_elided_brace_command_arg);
     722            add_to_element_args (current, e);
     723            arg = new_element (ET_raw);
     724            text_append (&arg->text, "");
     725            add_to_element_contents (e, arg);
     726  
     727            while (brace_count > 0)
     728              {
     729                size_t non_separator_len = strcspn (line, "{}");
     730                if (non_separator_len > 0)
     731                  text_append_n (&arg->text, line, non_separator_len);
     732                line += non_separator_len;
     733                switch (*line)
     734                  {
     735                  case '{':
     736                    brace_count++;
     737                    text_append_n (&arg->text, line, 1);
     738                    break;
     739                  case '}':
     740                    brace_count--;
     741                    if (brace_count > 0)
     742                      text_append_n (&arg->text, line, 1);
     743                    break;
     744                  default:
     745                    /* at the end of line */
     746                    free (alloc_line);
     747                    line = alloc_line = next_text (e);
     748                    if (!alloc_line)
     749                      goto funexit;
     750                    continue;
     751                  }
     752                line++;
     753              }
     754            counter_dec (&count_remaining_args);
     755            current = last_args_child (current);
     756            line--;  /* on '}' */
     757            goto funexit;
     758          }
     759      }
     760  
     761    if (counter_value (&count_remaining_args, current) != COUNTER_VARIADIC)
     762      counter_dec (&count_remaining_args);
     763    new_arg = new_element (type);
     764    add_to_element_args (current, new_arg);
     765    current = new_arg;
     766    e = new_element (ET_internal_spaces_before_argument);
     767    text_append (&e->text, ""); /* See comment in parser.c:merge_text */
     768    add_to_element_contents (current, e);
     769    add_extra_element (e, "spaces_associated_command", current);
     770    
     771  funexit:
     772    *line_inout = line;
     773    return current;
     774  }
     775