code:
/* Copyright 2010, 2011, 2012, 2013, 2014, 2015
   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 <http://www.gnu.org/licenses/>. */
#include <stdlib.h>
#include <string.h>

#include "parser.h"
#include "errors.h"

// 1246
/* Possibly print an error message, and return CURRENT->parent. */
static ELEMENT *
close_brace_command (ELEMENT *current,
                     enum command_id closed_command,
                     enum command_id interrupting_command)
{
  if (current->cmd != CM_verb || current->type == ET_NONE)
    {
      if (closed_command)
        command_error (current,
                        "@end %s seen before @%s closing brace",
                        command_name(closed_command),
                        command_name(current->cmd));
      else if (interrupting_command)
        command_error (current,
                        "@%s seen before @%s closing brace",
                        command_name(interrupting_command),
                        command_name(current->cmd));
      else
        command_error (current,
                        "@%s missing closing brace",
                        command_name(current->cmd));
    }
  else
    {
      char s[2];
      if ((char) current->type)
        {
          s[0] = (char) current->type;
          s[1] = 0;
        }
      else
        s[0] = 0;

      command_error (current,
                      "@%s missing closing delimiter sequence: %s}",
                      command_name(current->cmd), s);
    }
  current = current->parent;
  return current;
}

// 1292
/* Close out any brace commands that mark text, not allowing multiple
   paragraphs. */
ELEMENT *
close_all_style_commands (ELEMENT *current,
                          enum command_id closed_command,
                          enum command_id interrupting_command)
{
  while (current->parent
         && (command_flags(current->parent) & CF_brace)
         && !(command_data(current->parent->cmd).data == BRACE_context))
    current = close_brace_command (current->parent,
                                   closed_command, interrupting_command);

  return current;
}

// 1512
void
close_command_cleanup (ELEMENT *current)
{
  if (!current->cmd)
    return;

  // 1520
  if (current->cmd == CM_multitable)
    {
      int in_head_or_rows = -1, i;
      ELEMENT_LIST old_contents = current->contents;

      /* Clear current contents. */
      memset (&current->contents, 0, sizeof (ELEMENT_LIST));

      /* Rearrange the contents of the multitable to collect rows into
         ET_multitable_head and ET_multitable_body elements. */
      for (i = 0; i < old_contents.number; i++)
        {
          ELEMENT *row = old_contents.list[i];

          if (counter_value (&count_cells, row) != -1)
            counter_pop (&count_cells);

          if (row->type == ET_row)
            {
              /* Check if we need to open a new container. */
              if (contents_child_by_index (row, 0)->cmd == CM_headitem)
                {
                  if (in_head_or_rows <= 0)
                    {
                      add_to_element_contents (current,
                                        new_element (ET_multitable_head));
                      in_head_or_rows = 1;
                    }
                }
              else if (contents_child_by_index (row, 0)->cmd == CM_item)
                {
                  if (in_head_or_rows == 1 || in_head_or_rows == -1)
                    {
                      add_to_element_contents (current,
                                        new_element (ET_multitable_body));
                      in_head_or_rows = 0;
                    }
                }

              add_to_element_contents (last_contents_child(current), row);
            }
          else
            {
              add_to_element_contents (current, row);
              in_head_or_rows = -1;
            }
        }
      free (old_contents.list);

    }
  else if (current->cmd == CM_itemize || current->cmd == CM_enumerate)
    {
      counter_pop (&count_items);
    }

  /* Put everything after the last @def*x command in a def_item type
     container. */
  if (command_data(current->cmd).flags & CF_def)
    {
      gather_def_item (current, 0);
    }

  if (current->cmd == CM_table
      || current->cmd == CM_ftable
      || current->cmd == CM_vtable)
    {
      if (current->contents.number > 0)
        gather_previous_item (current, 0);
    }

  // 1570
  /* Block commands that contain @item's - e.g. @multitable, @table,
     @itemize. */
  if (command_data(current->cmd).flags & CF_blockitem
      && current->contents.number > 0)
    {
      int have_leading_spaces = 0;
      ELEMENT *before_item;
      if (current->contents.number >= 0
          && current->contents.list[0]->type == ET_empty_line_after_command
          && current->contents.list[1]->type == ET_before_item)
        {
          have_leading_spaces = 1;
          before_item = current->contents.list[1];
        }
      else
        {
          before_item = current->contents.list[0];
          /* TODO: before_item is ELEMENT or ELEMENT * ? */
        }

      /* Perl code here checks if before_item exists, but it already assumed
         that it existed by accessing 'type' key on it. */

      // 1585
      /* Reparent @end from a ET_before_item to the block command */
      {
      KEY_PAIR *k = lookup_extra_key (current, "end_command");
      ELEMENT *e = k ? k->value : 0;
      if (k && last_contents_child (before_item)
          && last_contents_child (before_item) == e)
        {
          add_to_element_contents (current,
                                   pop_element_from_contents (before_item));
        }
      }

      /* Now if the ET_before_item is empty, remove it. */
      if (before_item->contents.number == 0)
        {
          destroy_element (remove_from_contents (current,
                                                 have_leading_spaces ? 1 : 0));
        }
      else /* Non-empty ET_before_item */
        {
          int empty_before_item = 1, i;
          /* Check if contents consist soley of @comment's. */
          for (i = 0; i < before_item->contents.number; i++)
            {
              enum command_id c = before_item->contents.list[i]->cmd;
              if (c != CM_c && c != CM_comment)
                {
                  empty_before_item = 0;
                }
            }

          if (!empty_before_item)
            {
              int empty_format = 1;
              /* Check for an element that could represent an @item in the
                 block.  The type of this element will depend on the block
                 command we are in. */
              for (i = 0; i < current->contents.number; i++)
                {
                  ELEMENT *e = current->contents.list[i];
                  if (e == before_item)
                    continue;
                  if (e->cmd != CM_NONE
                         && (e->cmd != CM_c && e->cmd != CM_comment
                             && e->cmd != CM_end)
                      || e->type != CM_NONE
                         && e->type != ET_empty_line_after_command)
                    {
                      empty_format = 0;
                      break;
                    }
                }

              if (empty_format)
                command_warn (current, "@%s has text but no @item",
                              command_name(current->cmd));
            }
        }

    } // 1635
}

/* 1642 */
ELEMENT *
close_current (ELEMENT *current,
               enum command_id closed_command,
               enum command_id interrupting_command)
{
  /* Element is a command */
  if (current->cmd)
    {
      debug ("CLOSING (close_current) %s", command_name(current->cmd));
      if (command_flags(current) & CF_brace)
        {
          if (command_data(current->cmd).data == BRACE_context)
            pop_context ();
          current = close_brace_command (current,
                                         closed_command, interrupting_command);
        }
      else if (command_flags(current) & CF_block)
        {
          enum command_id cmd = current->cmd;
          ELEMENT *parent = 0;
          if (closed_command)
            {
              line_error ("`@end' expected `%s', but saw `%s'",
                          command_name(current->cmd),
                          command_name(closed_command));
            }
          else if (interrupting_command)
            {
              line_error ("@%s seen before @end %s",
                          command_name(interrupting_command),
                          command_name(current->cmd));
            }
          else
            {
              line_error ("no matching `@end %s'",
                          command_name(current->cmd));

              /* Ignored conditional. */
              if (command_data(current->cmd).data == BLOCK_conditional)
                {
                  parent = current->parent;
                  destroy_element (pop_element_from_contents (parent));
                }
              /* FIXME: Why not avoid adding the element
                 in the first place? */
            }
          if (command_data(cmd).flags
              & (CF_preformatted | CF_menu | CF_format_raw))
            {
              pop_context ();
            }
          if (command_data(cmd).flags & CF_region)
            {
              pop_region ();
            }
          if (!parent)
            parent = current->parent;
          current = parent;
        }
      else
        {
          /* @item and @tab commands are closed here, as well as line commands
             with invalid content. */
          current = current->parent;
        }
    }
  else if (current->type != ET_NONE)
    {
      enum context c;
      debug ("CLOSING type %s", element_type_names[current->type]);
      switch (current->type)
        {
        case ET_bracketed:
          command_error (current, "misplaced {");
          current = current->parent;
          break;
        case ET_menu_comment:
        case ET_menu_entry_description:
          c = pop_context ();
          if (c != ct_preformatted)
            abort ();

          /* 1700 Remove empty menu_comment */
          if (current->contents.number == 0)
            {
              current = current->parent;
              destroy_element (pop_element_from_contents (current));
            }
          else
            current = current->parent;

          break;
        case ET_misc_line_arg:
        case ET_block_line_arg:
          c = pop_context ();
          if (c != ct_line && c != ct_def)
            {
              /* error */
              abort ();
            }
          current = current->parent;
          break;
        default:
          current = current->parent;
          break;
        }
    }
  else
    {
      /* should never get here */
      if (current->parent)
        current = current->parent;
    }

  return current;
}

/* 1725 */
/* Return lowest level ancestor of CURRENT containing a CLOSED_COMMAND
   element.  Set CLOSED_ELEMENT to the element itself.  INTERRUPTING is used in
   close_brace_command 1246 to display an error message.  Remove a context from
   context stack if it was added by this command. */
ELEMENT *
close_commands (ELEMENT *current, enum command_id closed_command,
                ELEMENT **closed_element, enum command_id interrupting)
{
  *closed_element = 0;
  current = end_paragraph (current, closed_command, interrupting);
  current = end_preformatted (current, closed_command, interrupting);

  while (current->parent
         && (!closed_command || current->cmd != closed_command)
     /* Stop if in a root command. */
         && !(current->cmd && command_flags(current) & CF_root))
    {
      close_command_cleanup (current);
      current = close_current (current, closed_command, interrupting);
    }

  if (closed_command && current->cmd == closed_command)
    {
      /* 1758 - various error messages */
      if (command_data(current->cmd).flags & CF_preformatted)
        {
          if (pop_context () != ct_preformatted)
            abort ();
        }
      else if (command_data(current->cmd).flags & CF_format_raw)
        {
          if (pop_context () != ct_rawpreformatted)
            abort ();
          // pop expanded formats stack
        }
      else if (command_data(current->cmd).flags & CF_menu)
        {
          enum context c;
          c = pop_context ();
          if (c != ct_menu && c != ct_preformatted)
            abort ();
        }

      // 1784
      if (command_data(current->cmd).flags & CF_region)
        pop_region ();

      *closed_element = current;
      current = current->parent; /* 1788 */
    }
  else if (closed_command)
    {
      line_error ("unmatched `@end %s'", command_name(closed_command));
    }

  return current;
}


code:
# Copyright 2010, 2011, 2012, 2013, 2014, 2015
# 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 <http://www.gnu.org/licenses/>.
#

#######################################################
# From gawk manual
# ord.awk --- do ord and chr

# Global identifiers:
#    _ord_:        numerical values indexed by characters
#    _ord_init:    function to initialize _ord_

BEGIN    { _ord_init() }

function _ord_init(    low, high, i, t)
{
    low = sprintf("%c", 7) # BEL is ascii 7
    if (low == "\a") {    # regular ascii
        low = 0
        high = 127
    } else if (sprintf("%c", 128 + 7) == "\a") {
        # ascii, mark parity
        low = 128
        high = 255
    } else {        # ebcdic(!)
        low = 0
        high = 255
    }

    for (i = low; i <= high; i++) {
        t = sprintf("%c", i)
        _ord_[t] = i
    }
}

function ord(str,    c)
{
    # only first character is of interest
    c = substr(str, 1, 1)
    return _ord_[c]
}

#######################################################

BEGIN {
    bs_escapes["\\n"] = "\n"
    bs_escapes["\\f"] = "\f"
    bs_escapes["\\t"] = "\t"
    bs_escapes["\\\\"] = "\\"
    bs_escapes["\\\""] = "\""
    bs_escapes["\\x20"] = " "

    for (v in bs_escapes) {
        inv_bs_escapes[bs_escapes[v]] = v
    }

    print "/* This file automatically generated by command_data.awk */"
    print
    print "/* Useful aliases */"
    print "#define CM_hex_09 CM_TAB"
    print "#define CM_hex_0a CM_NEWLINE"
    print "#define CM_hex_20 CM_SPACE"
    print "#define CM_hex_21 CM_EXCLAMATION_MARK"
    print "#define CM_hex_22 CM_POUND_SIGN"
    print "#define CM_hex_27 CM_APOSTROPHE"
    print "#define CM_hex_2a CM_ASTERISK"
    print "#define CM_hex_2c CM_COMMA"
    print "#define CM_hex_2d CM_HYPHEN"
    print "#define CM_hex_2e CM_FULL_STOP"
    print "#define CM_hex_2f CM_SLASH"
    print "#define CM_hex_3a CM_COLON"
    print "#define CM_hex_3d CM_EQUALS"
    print "#define CM_hex_3f CM_QUESTION_MARK"
    print "#define CM_hex_40 CM_AT_SIGN"
    print "#define CM_hex_5c CM_BACKSLASH"
    print "#define CM_hex_5e CM_CIRCUMFLEX"
    print "#define CM_hex_60 CM_BACKQUOTE"
    print "#define CM_hex_7b CM_OPEN_BRACE"
    print "#define CM_hex_7c CM_VERTICAL_BAR"
    print "#define CM_hex_7d CM_CLOSE_BRACE"
    print "#define CM_hex_7e CM_TILDE"
    print
    print "enum command_id {"
    print "CM_NONE,"
    print
}

!/^$/ && !/^#/ {
    if ($1 in bs_escapes) {
        c = bs_escapes[$1]
    } else {
        c = $1
    }
    commands[c] = $2
    data[c] = $3
}

END {
    print "COMMAND builtin_command_data[] = {" >"command_data.c"

    print "0, 0, 0," >"command_data.c"

    # We want the output sorted so we can use bsearch
    PROCINFO["sorted_in"]="@ind_str_asc"
    for (c in commands) {
        # Single character commands with unusual names
        if (c ~ /^[^[:alpha:]]$/) {
                if (c in inv_bs_escapes) {
                    c2 = inv_bs_escapes[c]
                } else
                    c2 = c
                printf "CM_hex_%02x,\n", ord(c)
        } else {
                c2 = c
                print "CM_" c ","
        }

        if (commands[c] != "") {
            flags = "CF_" commands[c]
            gsub (/,/, " | CF_", flags)
        } else {
            flags = "0"
        }

        if (data[c] != "") {
            command_data = data[c]
        } else {
            command_data = "0"
        }
        print "\"" c2 "\", " flags ", " command_data "," > "command_data.c"
    }
    print "};" >"command_data.c"
    print "};"
}

repo_name: mthl/texinfo

license: mit


code:
# Copyright 2010, 2011, 2012, 2013, 2014, 2015
# Free Software Foundation, Inc.
#
# This file is part of GNU Texinfo.
#
# GNU Texinfo 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 <http://www.gnu.org/licenses/>.

# Information from tp/Texinfo/Common.pm

# Not in Common.pm
value	brace

##############################################################
# line 353 - no brace commands - single letter commands

*	nobrace
# space
\x20	nobrace
\t	nobrace
\n	nobrace
-	nobrace
|	nobrace
/	nobrace
:	nobrace
!	nobrace
?	nobrace
.	nobrace
@	nobrace
}	nobrace
{	nobrace
\\	nobrace

##############################################################
# line 405 - misc commands. line commands without an @end.
node    		misc		MISC_line
bye     		misc		MISC_skipline
end     		misc		MISC_text
# set, clear
set     		misc		MISC_special
clear   		misc		MISC_special
unmacro 		misc		MISC_special
# comments
c	 		misc		MISC_lineraw
comment 		misc		MISC_lineraw
# special
definfoenclose		misc		3
alias   		misc		2
# number of arguments is not known in advance.
columnfractions		misc		1
# file names
setfilename		misc,global_unique		MISC_text
verbatiminclude		misc		MISC_text
include 		misc		MISC_text

raisesections			misc		MISC_skipline
lowersections			misc		MISC_skipline
contents			misc,global		MISC_skipline
shortcontents			misc,global		MISC_skipline
summarycontents			misc,global		MISC_skipline
insertcopying			misc,global		MISC_noarg
clickstyle			misc,global		MISC_special
# more relevant in preamble
setcontentsaftertitlepage	misc,global_unique		MISC_skipline
setshortcontentsaftertitlepage	misc,global_unique		MISC_skipline
documentencoding		misc,global	MISC_text
novalidate			misc,global_unique	MISC_skipline
validatemenus			misc,global_unique     	1
dircategory			misc		MISC_line
# with direntry is significant
pagesizes			misc,global_unique	MISC_line
# or one? 200mm,150mm 11.5in
finalout			misc		MISC_skipline
paragraphindent			misc,global		1
# or a number and forbids anything else on the line
firstparagraphindent		misc,global		1
frenchspacing			misc,global		1
codequoteundirected		misc,global		1
codequotebacktick		misc,global		1
xrefautomaticsectiontitle	misc,global		1
deftypefnnewline		misc,global		1
fonttextsize			misc,global_unique		1
allowcodebreaks			misc,global       		1
exampleindent			misc,global		1
footnotestyle			misc,global_unique		1
urefbreakstyle			misc,global		1
afourpaper			misc		MISC_skipline
afivepaper			misc		MISC_skipline
afourlatex			misc		MISC_skipline
afourwide			misc		MISC_skipline
headings			misc,global		1
setchapternewpage		misc,global_unique		1

# only relevant in TeX, and special
everyheading			misc,global_unique		MISC_lineraw
everyfooting			misc,global_unique		MISC_lineraw
evenheading			misc,global_unique		MISC_lineraw
evenfooting			misc,global_unique		MISC_lineraw
oddheading			misc,global_unique		MISC_lineraw
oddfooting			misc,global_unique		MISC_lineraw

smallbook			misc		MISC_skipline
syncodeindex			misc		2
synindex			misc		2
defindex			misc		1
defcodeindex			misc		1
documentlanguage		misc,global		MISC_text
kbdinputstyle			misc,global		1
everyheadingmarks		misc,global_unique		1
everyfootingmarks		misc,global_unique		1
evenheadingmarks		misc,global_unique		1
oddheadingmarks			misc,global_unique		1
evenfootingmarks		misc,global_unique		1
oddfootingmarks			misc,global_unique		1
# not valid for info (should be in @iftex)
cropmarks			misc		MISC_skipline

# formatting
center				misc		MISC_line
printindex			misc,global		1
listoffloats			misc,global		MISC_line
# especially in titlepage
#  shorttitle
shorttitlepage			misc,global_unique	MISC_line
settitle			misc,global_unique	MISC_line
author				misc,global		MISC_line
subtitle			misc,global		MISC_line
title				misc,global_unique	MISC_line
sp				misc		1
page				misc		MISC_skipline
need				misc		1
# formatting
noindent			misc		MISC_skipspace
indent				misc		MISC_skipspace
exdent				misc		MISC_line
headitem			misc		MISC_skipspace
item				misc		MISC_skipspace
itemx				misc		MISC_skipspace
tab				misc		MISC_skipspace
# only valid in heading or footing
thischapter			misc,in_heading		MISC_noarg
thischaptername			misc,in_heading		MISC_noarg
thischapternum			misc,in_heading		MISC_noarg
thisfile			misc,in_heading		MISC_noarg
thispage			misc,in_heading		MISC_noarg
thistitle			misc,in_heading		MISC_noarg
# not valid for info (should be in @iftex)
vskip				misc		MISC_lineraw
# obsolete @-commands.
refill				misc		MISC_noarg
# Remove spaces and end of lines after the
# commands? If no, they can lead to empty lines
# TODO: Check what these two are.
# They were obsolete and undocumented commands for macro definitions,
# never supported in texinfo.tex.
#quote-arg			misc,deprecated		MISC_skipline
#allow-recursion		misc,deprecated		MISC_skipline

# line 515
##########################################################

##########################################################
#
# line 555 - brace commands
#
##########################################################

# letter_no_arg_commands
aa		brace		0
AA		brace		0
ae		brace		0
oe		brace		0
AE		brace		0
OE		brace		0
o		brace		0
O		brace		0
ss		brace		0
l		brace		0
L		brace		0
DH		brace		0
dh		brace		0
TH		brace		0
th		brace		0

# no arg commands
TeX		brace		0
LaTeX		brace		0
bullet		brace		0
copyright	brace		0
registeredsymbol brace		0
dots		brace		0
enddots		brace		0
equiv		brace		0
error		brace		0
expansion	brace		0
arrow		brace		0
minus		brace		0
point		brace		0
print		brace		0
result		brace		0
today		brace		0
exclamdown	brace		0
questiondown	brace		0
pounds		brace		0
ordf		brace		0
ordm		brace		0
atchar		brace		0
lbracechar	brace		0
rbracechar	brace		0
backslashchar	brace		0
hashchar	brace		0
comma		brace		0
euro		brace		0
geq		brace		0
leq		brace		0
tie		brace		0
textdegree	brace		0
click		brace		0
quotedblleft	brace		0
quotedblright	brace		0
quoteleft   	brace		0
quoteright  	brace		0
quotedblbase	brace		0
quotesinglbase	brace		0
guillemetleft	brace		0
guillemetright	brace		0
guillemotleft	brace		0
guillemotright	brace		0
guilsinglleft	brace		0
guilsinglright	brace		0

# accent commands - can be called with or without braces
# TODO do we need "brace" here as well?
\"		brace,accent	BRACE_accent
~ 		brace,accent	BRACE_accent
^ 		brace,accent	BRACE_accent
` 		brace,accent	BRACE_accent
' 		brace,accent	BRACE_accent
, 		brace,accent	BRACE_accent
= 		brace,accent	BRACE_accent
ringaccent	brace,accent	BRACE_accent
H		brace,accent	BRACE_accent
dotaccent	brace,accent	BRACE_accent
u		brace,accent	BRACE_accent
ubaraccent	brace,accent	BRACE_accent
udotaccent	brace,accent	BRACE_accent
v		brace,accent	BRACE_accent
ogonek		brace,accent	BRACE_accent
tieaccent	brace,accent	BRACE_accent
dotless		brace,accent	BRACE_accent

# Style commands
asis		brace	BRACE_style
cite		brace	BRACE_style
clicksequence	brace	BRACE_style
dfn		brace	BRACE_style
emph		brace	BRACE_style
sc		brace	BRACE_style
t		brace	BRACE_style
var		brace	BRACE_style
headitemfont	brace	BRACE_style
code		brace,code_style	BRACE_style
command		brace,code_style,code_style	BRACE_style
env		brace,code_style,code_style	BRACE_style
file		brace,code_style,code_style	BRACE_style
kbd		brace,code_style,code_style	BRACE_style
option		brace,code_style,code_style	BRACE_style
samp		brace,code_style,code_style	BRACE_style
strong		brace	BRACE_style
sub		brace	BRACE_style
sup		brace	BRACE_style

# Regular font style commands 595
r		brace	BRACE_style
i		brace	BRACE_style
b		brace	BRACE_style
sansserif	brace	BRACE_style
slanted		brace	BRACE_style

# One arg, "simple text" argument commands
# I intend to use "1" for these commands only, and
# use a different value for the other commands which
# are said to take 1 argument in Common.pm.
U		brace	1
ctrl		brace,deprecated	1
dmn		brace	1
titlefont	brace,global	1

w		brace	BRACE_other
key		brace	BRACE_other

hyphenation	brace,global	BRACE_other
anchor		brace	1
errormsg	brace	1

# more code style commands
indicateurl	brace,code_style	1
verb		brace,code_style	BRACE_other
t		brace,code_style	BRACE_other

# context brace commands - commands that enclose full texts
footnote	brace,global	BRACE_context
caption		brace	BRACE_context
shortcaption	brace	BRACE_context
math		brace	BRACE_context

# explained commands 624
abbr		brace	2
acronym		brace	2

# inline format command
inlineraw		brace,inline	2
inlinefmt		brace,inline	2
inlinefmtifelse		brace,inline	3

# inline conditional commands
inlineifclear		brace,inline	2
inlineifset		brace,inline	2

email			brace	2

uref		brace		3
url		brace		3
inforef		brace,ref	3

xref		brace,ref	5
ref		brace,ref	5
pxref		brace,ref	5
image		brace		5

# line 660

##########################################################
# line 687 - "block commands"

# def* commands
deffn			block,def
defvr			block,def
deftypefn		block,def
deftypeop		block,def
deftypevr		block,def
defcv			block,def
deftypecv		block,def
defop			block,def
deftp			block,def
#   shortcuts
defun			block,def,def_alias
defmac			block,def,def_alias
defspec			block,def,def_alias
defvar			block,def,def_alias
defopt			block,def,def_alias
deftypefun		block,def,def_alias
deftypevar		block,def,def_alias
defivar			block,def,def_alias
deftypeivar		block,def,def_alias
defmethod		block,def,def_alias
deftypemethod		block,def,def_alias

# def*x
deffnx			misc,def                MISC_line
defvrx			misc,def                MISC_line
deftypefnx		misc,def                MISC_line
deftypeopx		misc,def                MISC_line
deftypevrx		misc,def                MISC_line
defcvx			misc,def                MISC_line
deftypecvx		misc,def                MISC_line
defopx			misc,def                MISC_line
deftpx			misc,def                MISC_line
#   shortcuts
defunx			misc,def,def_alias              MISC_line
defmacx			misc,def,def_alias              MISC_line
defspecx		misc,def,def_alias              MISC_line
defvarx			misc,def,def_alias              MISC_line
defoptx			misc,def,def_alias              MISC_line
deftypefunx		misc,def,def_alias              MISC_line
deftypevarx		misc,def,def_alias              MISC_line
defivarx		misc,def,def_alias              MISC_line
deftypeivarx		misc,def,def_alias              MISC_line
defmethodx		misc,def,def_alias              MISC_line
deftypemethodx		misc,def,def_alias              MISC_line

# 760
multitable		block,blockitem		BLOCK_multitable

# menu commands
menu			block,menu
detailmenu		block,menu,global
direntry		block,menu

# align commands
raggedright		block
flushleft		block
flushright		block

# 777
cartouche		block
group			block
indentedblock		block
smallindentedblock	block

# region commands
titlepage		block,global_unique,region
copying			block,global_unique,region
documentdescription	block,global_unique,region

# preformatted commands
example			block,preformatted,preformatted_code
smallexample		block,preformatted,preformatted_code
lisp			block,preformatted,preformatted_code
smalllisp		block,preformatted,preformatted_code
display			block,preformatted
smalldisplay		block,preformatted
format			block,preformatted
smallformat		block,preformatted

# format raw commands
html			block,format_raw
tex			block,format_raw
xml			block,format_raw
docbook			block,format_raw

# raw commands 811
verbatim		block		BLOCK_raw
ignore			block		BLOCK_raw
macro			block		BLOCK_raw
rmacro			block		BLOCK_raw

# line 815

# line 831
table		block,blockitem		1
ftable		block,blockitem		1
vtable		block,blockitem		1
itemize		block,blockitem		1
enumerate	block,blockitem		1
quotation	block			1
smallquotation	block			1

float	block	2

##################################################################
# Conditional commands
ifhtml			block		BLOCK_conditional
ifnothtml		block		BLOCK_conditional
iftex			block		BLOCK_conditional
ifnottex		block		BLOCK_conditional
ifxml			block		BLOCK_conditional
ifnotxml		block		BLOCK_conditional
ifdocbook		block		BLOCK_conditional
ifnotdocbook		block		BLOCK_conditional
ifinfo			block		BLOCK_conditional
ifnotinfo		block		BLOCK_conditional
ifplaintext		block		BLOCK_conditional
ifnotplaintext		block		BLOCK_conditional
ifset			block		BLOCK_conditional
ifclear			block		BLOCK_conditional
ifcommanddefined	block		BLOCK_conditional
ifcommandnotdefined	block		BLOCK_conditional

##########################################################
# Root commands - line 887
node			root,misc			MISC_line
top			root,misc,sectioning,global_unique	MISC_line
chapter			root,misc,sectioning		MISC_line
unnumbered		root,misc,sectioning		MISC_line
chapheading		misc,sectioning			MISC_line
appendix		root,misc,sectioning		MISC_line
section			root,misc,sectioning		MISC_line
unnumberedsec		root,misc,sectioning		MISC_line
heading			misc,sectioning			MISC_line
appendixsec		root,misc,sectioning		MISC_line
subsection		root,misc,sectioning		MISC_line
unnumberedsubsec	root,misc,sectioning		MISC_line
subheading		misc,sectioning			MISC_line
appendixsubsec		root,misc,sectioning		MISC_line
subsubsection		root,misc,sectioning		MISC_line
unnumberedsubsubsec	root,misc,sectioning		MISC_line
subsubheading		misc,sectioning			MISC_line
appendixsubsubsec	root,misc,sectioning		MISC_line

part			root,misc,sectioning,global	MISC_line
appendixsection		root,misc,sectioning	MISC_line
majorheading		misc,sectioning		MISC_line
centerchap		root,misc,sectioning	MISC_line


code:
/* This file automatically generated by command_data.awk */

/* Useful aliases */
#define CM_hex_09 CM_TAB
#define CM_hex_0a CM_NEWLINE
#define CM_hex_20 CM_SPACE
#define CM_hex_21 CM_EXCLAMATION_MARK
#define CM_hex_22 CM_POUND_SIGN
#define CM_hex_27 CM_APOSTROPHE
#define CM_hex_2a CM_ASTERISK
#define CM_hex_2c CM_COMMA
#define CM_hex_2d CM_HYPHEN
#define CM_hex_2e CM_FULL_STOP
#define CM_hex_2f CM_SLASH
#define CM_hex_3a CM_COLON
#define CM_hex_3d CM_EQUALS
#define CM_hex_3f CM_QUESTION_MARK
#define CM_hex_40 CM_AT_SIGN
#define CM_hex_5c CM_BACKSLASH
#define CM_hex_5e CM_CIRCUMFLEX
#define CM_hex_60 CM_BACKQUOTE
#define CM_hex_7b CM_OPEN_BRACE
#define CM_hex_7c CM_VERTICAL_BAR
#define CM_hex_7d CM_CLOSE_BRACE
#define CM_hex_7e CM_TILDE

enum command_id {
CM_NONE,

CM_hex_09,
CM_hex_0a,
CM_hex_20,
CM_hex_21,
CM_hex_22,
CM_hex_27,
CM_hex_2a,
CM_hex_2c,
CM_hex_2d,
CM_hex_2e,
CM_hex_2f,
CM_hex_3a,
CM_hex_3d,
CM_hex_3f,
CM_hex_40,
CM_AA,
CM_AE,
CM_DH,
CM_H,
CM_L,
CM_LaTeX,
CM_O,
CM_OE,
CM_TH,
CM_TeX,
CM_U,
CM_hex_5c,
CM_hex_5e,
CM_hex_60,
CM_aa,
CM_abbr,
CM_acronym,
CM_ae,
CM_afivepaper,
CM_afourlatex,
CM_afourpaper,
CM_afourwide,
CM_alias,
CM_allowcodebreaks,
CM_anchor,
CM_appendix,
CM_appendixsec,
CM_appendixsection,
CM_appendixsubsec,
CM_appendixsubsubsec,
CM_arrow,
CM_asis,
CM_atchar,
CM_author,
CM_b,
CM_backslashchar,
CM_bullet,
CM_bye,
CM_c,
CM_caption,
CM_cartouche,
CM_center,
CM_centerchap,
CM_chapheading,
CM_chapter,
CM_cite,
CM_clear,
CM_click,
CM_clicksequence,
CM_clickstyle,
CM_code,
CM_codequotebacktick,
CM_codequoteundirected,
CM_columnfractions,
CM_comma,
CM_command,
CM_comment,
CM_contents,
CM_copying,
CM_copyright,
CM_cropmarks,
CM_ctrl,
CM_defcodeindex,
CM_defcv,
CM_defcvx,
CM_deffn,
CM_deffnx,
CM_defindex,
CM_definfoenclose,
CM_defivar,
CM_defivarx,
CM_defmac,
CM_defmacx,
CM_defmethod,
CM_defmethodx,
CM_defop,
CM_defopt,
CM_defoptx,
CM_defopx,
CM_defspec,
CM_defspecx,
CM_deftp,
CM_deftpx,
CM_deftypecv,
CM_deftypecvx,
CM_deftypefn,
CM_deftypefnnewline,
CM_deftypefnx,
CM_deftypefun,
CM_deftypefunx,
CM_deftypeivar,
CM_deftypeivarx,
CM_deftypemethod,
CM_deftypemethodx,
CM_deftypeop,
CM_deftypeopx,
CM_deftypevar,
CM_deftypevarx,
CM_deftypevr,
CM_deftypevrx,
CM_defun,
CM_defunx,
CM_defvar,
CM_defvarx,
CM_defvr,
CM_defvrx,
CM_detailmenu,
CM_dfn,
CM_dh,
CM_dircategory,
CM_direntry,
CM_display,
CM_dmn,
CM_docbook,
CM_documentdescription,
CM_documentencoding,
CM_documentlanguage,
CM_dotaccent,
CM_dotless,
CM_dots,
CM_email,
CM_emph,
CM_end,
CM_enddots,
CM_enumerate,
CM_env,
CM_equiv,
CM_error,
CM_errormsg,
CM_euro,
CM_evenfooting,
CM_evenfootingmarks,
CM_evenheading,
CM_evenheadingmarks,
CM_everyfooting,
CM_everyfootingmarks,
CM_everyheading,
CM_everyheadingmarks,
CM_example,
CM_exampleindent,
CM_exclamdown,
CM_exdent,
CM_expansion,
CM_file,
CM_finalout,
CM_firstparagraphindent,
CM_float,
CM_flushleft,
CM_flushright,
CM_fonttextsize,
CM_footnote,
CM_footnotestyle,
CM_format,
CM_frenchspacing,
CM_ftable,
CM_geq,
CM_group,
CM_guillemetleft,
CM_guillemetright,
CM_guillemotleft,
CM_guillemotright,
CM_guilsinglleft,
CM_guilsinglright,
CM_hashchar,
CM_heading,
CM_headings,
CM_headitem,
CM_headitemfont,
CM_html,
CM_hyphenation,
CM_i,
CM_ifclear,
CM_ifcommanddefined,
CM_ifcommandnotdefined,
CM_ifdocbook,
CM_ifhtml,
CM_ifinfo,
CM_ifnotdocbook,
CM_ifnothtml,
CM_ifnotinfo,
CM_ifnotplaintext,
CM_ifnottex,
CM_ifnotxml,
CM_ifplaintext,
CM_ifset,
CM_iftex,
CM_ifxml,
CM_ignore,
CM_image,
CM_include,
CM_indent,
CM_indentedblock,
CM_indicateurl,
CM_inforef,
CM_inlinefmt,
CM_inlinefmtifelse,
CM_inlineifclear,
CM_inlineifset,
CM_inlineraw,
CM_insertcopying,
CM_item,
CM_itemize,
CM_itemx,
CM_kbd,
CM_kbdinputstyle,
CM_key,
CM_l,
CM_lbracechar,
CM_leq,
CM_lisp,
CM_listoffloats,
CM_lowersections,
CM_macro,
CM_majorheading,
CM_math,
CM_menu,
CM_minus,
CM_multitable,
CM_need,
CM_node,
CM_noindent,
CM_novalidate,
CM_o,
CM_oddfooting,
CM_oddfootingmarks,
CM_oddheading,
CM_oddheadingmarks,
CM_oe,
CM_ogonek,
CM_option,
CM_ordf,
CM_ordm,
CM_page,
CM_pagesizes,
CM_paragraphindent,
CM_part,
CM_point,
CM_pounds,
CM_print,
CM_printindex,
CM_pxref,
CM_questiondown,
CM_quotation,
CM_quotedblbase,
CM_quotedblleft,
CM_quotedblright,
CM_quoteleft,
CM_quoteright,
CM_quotesinglbase,
CM_r,
CM_raggedright,
CM_raisesections,
CM_rbracechar,
CM_ref,
CM_refill,
CM_registeredsymbol,
CM_result,
CM_ringaccent,
CM_rmacro,
CM_samp,
CM_sansserif,
CM_sc,
CM_section,
CM_set,
CM_setchapternewpage,
CM_setcontentsaftertitlepage,
CM_setfilename,
CM_setshortcontentsaftertitlepage,
CM_settitle,
CM_shortcaption,
CM_shortcontents,
CM_shorttitlepage,
CM_slanted,
CM_smallbook,
CM_smalldisplay,
CM_smallexample,
CM_smallformat,
CM_smallindentedblock,
CM_smalllisp,
CM_smallquotation,
CM_sp,
CM_ss,
CM_strong,
CM_sub,
CM_subheading,
CM_subsection,
CM_subsubheading,
CM_subsubsection,
CM_subtitle,
CM_summarycontents,
CM_sup,
CM_syncodeindex,
CM_synindex,
CM_t,
CM_tab,
CM_table,
CM_tex,
CM_textdegree,
CM_th,
CM_thischapter,
CM_thischaptername,
CM_thischapternum,
CM_thisfile,
CM_thispage,
CM_thistitle,
CM_tie,
CM_tieaccent,
CM_title,
CM_titlefont,
CM_titlepage,
CM_today,
CM_top,
CM_u,
CM_ubaraccent,
CM_udotaccent,
CM_unmacro,
CM_unnumbered,
CM_unnumberedsec,
CM_unnumberedsubsec,
CM_unnumberedsubsubsec,
CM_uref,
CM_urefbreakstyle,
CM_url,
CM_v,
CM_validatemenus,
CM_value,
CM_var,
CM_verb,
CM_verbatim,
CM_verbatiminclude,
CM_vskip,
CM_vtable,
CM_w,
CM_xml,
CM_xref,
CM_xrefautomaticsectiontitle,
CM_hex_7b,
CM_hex_7c,
CM_hex_7d,
CM_hex_7e,
};


code:
/* Copyright 2010, 2011, 2012, 2013, 2014, 2015
   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 <http://www.gnu.org/licenses/>. */

#include <stdlib.h>
#include <string.h>

#include "command_ids.h"
#include "commands.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)
    return c - &builtin_command_data[0];

  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)
{
  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)
        abort ();
    }

  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;

  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;
  free (user_defined_command_data[cmd].cmdname);
  user_defined_command_data[cmd].cmdname = "";
}

void
wipe_user_commands (void)
{
  user_defined_number = 0;
}

/* Common.pm:841. */
/* Commands that terminate a paragraph. */
/* We may replace this function with a macro, or represent this infomation in
   command_data. */
int
close_paragraph_command (enum command_id cmd)
{
  if (cmd == CM_verbatim)
    return 1;

  /* Block commands except 'raw' and 'conditional'.  */

  if (command_data(cmd).flags & CF_block)
    {
      if (command_data(cmd).data == BLOCK_conditional
          || command_data(cmd).data == BLOCK_raw)
        return 0;
      if (command_data(cmd).flags & CF_format_raw)
        return 0;

      return 1;
    }

  /* several others Common.pm:852 */
  if (cmd == CM_titlefont
     || cmd == CM_insertcopying
     || cmd == CM_sp
     || cmd == CM_verbatiminclude
     || cmd == CM_page
     || cmd == CM_item
     || cmd == CM_itemx
     || cmd == CM_tab
     || cmd == CM_headitem
     || cmd == CM_printindex
     || cmd == CM_listoffloats
     || cmd == CM_center
     || cmd == CM_dircategory
     || cmd == CM_contents
     || cmd == CM_shortcontents
     || cmd == CM_summarycontents
     || cmd == CM_caption
     || cmd == CM_shortcaption
     || cmd == CM_setfilename
     || cmd == CM_exdent)
    return 1;

  /* headings Common.pm:954 */
  if ((command_data(cmd).flags & CF_sectioning)
      && !(command_data(cmd).flags & CF_root))
    return 1;

  /* def commands 866 */
  if ((command_data(cmd).flags & CF_def))
    return 1;

  return 0;
}

// Parser.pm:348
int
close_preformatted_command (enum command_id cmd_id)
{
  return cmd_id != CM_sp && close_paragraph_command (cmd_id);
}

int
item_line_command (enum command_id cmd_id)
{
  return cmd_id == CM_table || cmd_id == CM_ftable || cmd_id == CM_vtable;
}


code:
/* Copyright 2010, 2011, 2012, 2013, 2014, 2015
   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 <http://www.gnu.org/licenses/>. */

typedef struct command_struct {
    char *cmdname;
    unsigned long flags; /* Up to 32 flags */
    int data; /* Number of arguments for brace or line commands. */
} COMMAND;

extern COMMAND builtin_command_data[];
extern COMMAND *user_defined_command_data;

/* Command ID's with this bit set represent a user-defined command. */
#define USER_COMMAND_BIT 0x8000

enum command_id lookup_command (char *cmdname);

#define command_data(id) \
  (!((id) & USER_COMMAND_BIT) \
   ? builtin_command_data[(id)] \
   : user_defined_command_data[(id) & ~USER_COMMAND_BIT])

#define command_flags(e) (!(e) ? 0 : (command_data((e)->cmd).flags))
#define command_name(cmd) (command_data(cmd).cmdname)

enum command_id add_texinfo_command (char *name);
void remove_texinfo_command (enum command_id cmd);
void wipe_user_commands (void);

/* In indices.c */
void init_index_commands (void);

/* Available command flags.  Based on tp/Texinfo/Common.pm. */

#define CF_misc			        0x0001
#define CF_deprecated   	        0x0002
#define CF_root			        0x0004
#define CF_sectioning		        0x0008
#define CF_brace		        0x0010
#define CF_letter_no_arg	        0x0020
#define CF_accent		        0x0040
#define CF_style		        0x0080
/* CF_code_style is set for brace commands only. */
#define CF_code_style		        0x0100
#define CF_INFOENCLOSE  	        0x0200
#define CF_in_heading     	        0x0400
#define CF_ref			        0x0800
#define CF_ALIAS                        0x1000
#define CF_block		        0x2000
#define CF_raw			        0x4000
#define CF_format_raw		        0x8000
#define CF_global                	0x00010000
#define CF_def		        	0x00020000
#define CF_def_alias	        	0x00040000
#define CF_menu		        	0x00080000
#define CF_align	        	0x00100000
#define CF_region	        	0x00200000
#define CF_preformatted	        	0x00400000
#define CF_preformatted_code		0x00800000
#define CF_item_container		0x01000000
#define CF_item_line			0x02000000
#define CF_nobrace			0x04000000
#define CF_blockitem			0x08000000
#define CF_inline			0x10000000
#define CF_MACRO 			0x20000000
#define CF_index_entry_command  	0x40000000
#define CF_global_unique		0x80000000

/* NOTE: We've run out of spaces for flags, but some of these may not
   be used, or may not be necessary. For example, region could be done
   as BLOCK_region in data instead.
     CF_code_style, CF_deprecated are hardly used.

   Candidates for flags:
     CF_close_paragraph

   Could combine CF_MACRO, CF_ALIAS, and CF_INFOENCLOSE into 2 bits.
 */

/* Types of misc command (has CF_misc flag).  Values for COMMAND.data. */
/* See Common.pm:376 */
#define MISC_special -1
#define MISC_lineraw -2
#define MISC_skipline -3
#define MISC_skipspace -4
#define MISC_noarg -5
#define MISC_text -6
#define MISC_line -7

/* Types of block command (CF_block).  Common.pm:687. */
#define BLOCK_conditional -1
#define BLOCK_raw -2
#define BLOCK_multitable -3

/* Types of brace command (CF_brace). */
#define BRACE_context -1 /* Can enclose paragraph breaks. */
#define BRACE_accent -2
#define BRACE_style -3
#define BRACE_other -4


code:
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.

scriptversion=2012-10-14.11; # UTC

# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# 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, see <http://www.gnu.org/licenses/>.

# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.

# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.

nl='
'

# We need space, tab and new line, in precisely that order.  Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" ""	$nl"

file_conv=

# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
  file=$1
  case $file in
    / | /[!/]*) # absolute file, and not a UNC file
      if test -z "$file_conv"; then
	# lazily determine how to convert abs files
	case `uname -s` in
	  MINGW*)
	    file_conv=mingw
	    ;;
	  CYGWIN*)
	    file_conv=cygwin
	    ;;
	  *)
	    file_conv=wine
	    ;;
	esac
      fi
      case $file_conv/,$2, in
	*,$file_conv,*)
	  ;;
	mingw/*)
	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
	  ;;
	cygwin/*)
	  file=`cygpath -m "$file" || echo "$file"`
	  ;;
	wine/*)
	  file=`winepath -w "$file" || echo "$file"`
	  ;;
      esac
      ;;
  esac
}

# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
  func_file_conv "$1"
  if test -z "$lib_path"; then
    lib_path=$file
  else
    lib_path="$lib_path;$file"
  fi
  linker_opts="$linker_opts -LIBPATH:$file"
}

# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
  lib=$1
  found=no
  save_IFS=$IFS
  IFS=';'
  for dir in $lib_path $LIB
  do
    IFS=$save_IFS
    if $shared && test -f "$dir/$lib.dll.lib"; then
      found=yes
      lib=$dir/$lib.dll.lib
      break
    fi
    if test -f "$dir/$lib.lib"; then
      found=yes
      lib=$dir/$lib.lib
      break
    fi
    if test -f "$dir/lib$lib.a"; then
      found=yes
      lib=$dir/lib$lib.a
      break
    fi
  done
  IFS=$save_IFS

  if test "$found" != yes; then
    lib=$lib.lib
  fi
}

# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
  # Assume a capable shell
  lib_path=
  shared=:
  linker_opts=
  for arg
  do
    if test -n "$eat"; then
      eat=
    else
      case $1 in
	-o)
	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
	  eat=1
	  case $2 in
	    *.o | *.[oO][bB][jJ])
	      func_file_conv "$2"
	      set x "$@" -Fo"$file"
	      shift
	      ;;
	    *)
	      func_file_conv "$2"
	      set x "$@" -Fe"$file"
	      shift
	      ;;
	  esac
	  ;;
	-I)
	  eat=1
	  func_file_conv "$2" mingw
	  set x "$@" -I"$file"
	  shift
	  ;;
	-I*)
	  func_file_conv "${1#-I}" mingw
	  set x "$@" -I"$file"
	  shift
	  ;;
	-l)
	  eat=1
	  func_cl_dashl "$2"
	  set x "$@" "$lib"
	  shift
	  ;;
	-l*)
	  func_cl_dashl "${1#-l}"
	  set x "$@" "$lib"
	  shift
	  ;;
	-L)
	  eat=1
	  func_cl_dashL "$2"
	  ;;
	-L*)
	  func_cl_dashL "${1#-L}"
	  ;;
	-static)
	  shared=false
	  ;;
	-Wl,*)
	  arg=${1#-Wl,}
	  save_ifs="$IFS"; IFS=','
	  for flag in $arg; do
	    IFS="$save_ifs"
	    linker_opts="$linker_opts $flag"
	  done
	  IFS="$save_ifs"
	  ;;
	-Xlinker)
	  eat=1
	  linker_opts="$linker_opts $2"
	  ;;
	-*)
	  set x "$@" "$1"
	  shift
	  ;;
	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
	  func_file_conv "$1"
	  set x "$@" -Tp"$file"
	  shift
	  ;;
	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
	  func_file_conv "$1" mingw
	  set x "$@" "$file"
	  shift
	  ;;
	*)
	  set x "$@" "$1"
	  shift
	  ;;
      esac
    fi
    shift
  done
  if test -n "$linker_opts"; then
    linker_opts="-link$linker_opts"
  fi
  exec "$@" $linker_opts
  exit 1
}

eat=

case $1 in
  '')
     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
     exit 1;
     ;;
  -h | --h*)
    cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]

Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.

If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.

Report bugs to <bug-automake@gnu.org>.
EOF
    exit $?
    ;;
  -v | --v*)
    echo "compile $scriptversion"
    exit $?
    ;;
  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
    func_cl_wrapper "$@"      # Doesn't return...
    ;;
esac

ofile=
cfile=

for arg
do
  if test -n "$eat"; then
    eat=
  else
    case $1 in
      -o)
	# configure might choose to run compile as 'compile cc -o foo foo.c'.
	# So we strip '-o arg' only if arg is an object.
	eat=1
	case $2 in
	  *.o | *.obj)
	    ofile=$2
	    ;;
	  *)
	    set x "$@" -o "$2"
	    shift
	    ;;
	esac
	;;
      *.c)
	cfile=$1
	set x "$@" "$1"
	shift
	;;
      *)
	set x "$@" "$1"
	shift
	;;
    esac
  fi
  shift
done

if test -z "$ofile" || test -z "$cfile"; then
  # If no '-o' option was seen then we might have been invoked from a
  # pattern rule where we don't need one.  That is ok -- this is a
  # normal compilation that the losing compiler can handle.  If no
  # '.c' file was seen then we are probably linking.  That is also
  # ok.
  exec "$@"
fi

# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`

# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file.  Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
  if mkdir "$lockdir" >/dev/null 2>&1; then
    break
  fi
  sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15

# Run the compile.
"$@"
ret=$?

if test -f "$cofile"; then
  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi

rmdir "$lockdir"
exit $ret

# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

path: tp/parsetexi/compile


code:
#!/usr/bin/perl

# Don't know exactly what this is but it's probably a good idea.
use 5.006;
use strict;

use Data::Dumper;

sub add_parents ($) {
  my $elt = shift;

  if (exists $elt->{'contents'}) {
    foreach my $child (@{$elt->{'contents'}}) {
      $child->{'parent'} = $elt;
      add_parents ($child);
    }
  }

  if (exists $elt->{'args'}) {
    foreach my $child (@{$elt->{'args'}}) {
      $child->{'parent'} = $elt;
      add_parents ($child);
    }
  }
}

my $in_file = $ARGV[0];
my $tree_stream;

print "Getting tree...\n";

$tree_stream = qx(./parsetexi $in_file 2>/dev/null);
print "Got tree.\n";

my $VAR1;
print "Reading tree...\n";
eval $tree_stream;
print "Read tree.\n";

print "Adjusting tree...\n";
add_parents ($VAR1);
print "Adjusted tree.\n";

$Data::Dumper::Purity = 1;
$Data::Dumper::Indent = 1;
#my $bar = Data::Dumper->Dump([$VAR1], ['$VAR1']);
#print $bar;


code:
# configure.ac for Parsetexi
#
# Copyright 2016 Free Software Foundation, Inc.
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
AC_INIT([texinfo], [6.0])
AM_INIT_AUTOMAKE
AC_CONFIG_MACRO_DIR([m4])

fetch_conf ()
{
          conf_value=`${PERL} -V:$1`
          # This turns a string like "cc='cc';" into a string like "cc".
          # Afterwards, convert \ into / in case \ is a path separator,
          # so it is not interpreted as a special character by the shell.
          conf_value=`echo $conf_value \
              | sed -e 's/^@<:@^=@:>@*= *//'   \
                    -e 's/^'\\''//'            \
                    -e 's/ *; *$//'            \
                    -e 's/'\\''$//'            \
                    -e 's/\\\\/\\//g'          `
          #echo got "$conf_value"
}

AC_DEFUN([lookup_perl_conf],
         [AC_MSG_CHECKING([Perl configuration value $1])
          fetch_conf $1
          AC_MSG_RESULT([$conf_value])
          AC_SUBST([PERL_CONF_$1], [$conf_value])
])

AC_ARG_ENABLE([perl-xs],
    AC_HELP_STRING([--enable-perl-xs],
              [build Perl XS modules for speed (default: yes)]),
    [if test $enableval = 'no'; then
       disable_xs=yes
     else
       disable_xs=no
     fi],
     [disable_xs=no])

# See (automake)Conditional Subdirectories.  Even if --disable-perl-xs
# is given, we still need to configure this directory minimally, so that
# "make dist" will work.
if test x$disable_xs != xyes; then
  AC_PATH_PROG([PERL], [perl])

  # It's essential that we use the same compiler that was used to build
  # Perl.  Otherwise Perl's "config.h" will be incorrect.  This overrides
  # the check in AC_PROG_CC below.
  lookup_perl_conf([cc])
  CC=$conf_value

  # Wipe the cache value in case -C was given at the top level
  ac_cv_prog_CC= ; unset ac_cv_prog_CC
fi

AC_PROG_CC

gl_EARLY

AC_PATH_PROG([XSUBPP], [xsubpp])
if test x$ac_cv_path_XSUBPP = x ; then
  AC_MSG_ERROR([xsubpp not found])
fi

gl_INIT

LT_INIT

# The above are still necessary for --disable-perl-xs even though they
# aren't really used: otherwise, configure complains about undefined
# variables.

# User variables for a Perl XS extension, which may be different, for
# example if the Perl interpreter being used was compiled with a
# different compiler.  Also in top-level configure.ac.
AC_ARG_VAR([PERL_EXT_CFLAGS], [Compiler flags for a Perl extension])
AC_ARG_VAR([PERL_EXT_CPPFLAGS], [C preprocessor flags for a Perl extension])
AC_ARG_VAR([PERL_EXT_LDFLAGS], [Linker flags for a Perl extension])

if test x$disable_xs != xyes; then
lookup_perl_conf([ccflags])
lookup_perl_conf([cccdlflags])

# flags for linking the extension, e.g. -rpath.
lookup_perl_conf([ccdlflags])

lookup_perl_conf([libperl])
# Change libperl.so into -lperl to indicate a library dependency to
# libtool.
# Special case for Cygwin to change e.g. cygperl5_22.dll into -lperl
PERL_CONF_libperl=`echo $PERL_CONF_libperl \
           | sed -e 's/^lib/-l/' \
                 -e 's/\..*//' \
                 -e 's/^cygperl.*/-lperl/' `

lookup_perl_conf([archlibexp])
lookup_perl_conf([privlibexp])
# TODO: would be nice to be able to do lookup_perl_conf([ccflags cccdlflags])
# A for loop doesn't work; it has to be expanded at m4 time

AC_CONFIG_HEADERS([config.h:config.in])
fi # not disable_xs

AC_CONFIG_FILES([Makefile])
AC_OUTPUT


code:
/* Copyright 2010, 2011, 2012, 2013, 2014, 2015
   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 <http://www.gnu.org/licenses/>. */

#include <stdlib.h>

#include "tree_types.h"
#include "context_stack.h"
#include "api.h"

static enum context *stack;
static size_t top; /* One above last pushed context. */
static size_t space;

void
reset_context_stack (void)
{
  top = 0;
}

void
push_context (enum context c)
{
  if (top >= space)
    {
      stack = realloc (stack, (space += 5) * sizeof (enum context));
    }

  debug (">>>>>>>>>>>>>>>>>PUSHING STACK AT %d  -- %s", top,
         c == ct_preformatted ? "preformatted"
         : c == ct_line ? "line"
         : c == ct_def ? "def"
         : c == ct_menu ? "menu"
         : "");
  stack[top++] = c;
}

enum context
pop_context ()
{
  if (top == 0)
    abort ();

  debug (">>>>>>>>>>>>>POPPING STACK AT %d", top - 1);
  return stack[--top];
}

enum context
current_context (void)
{
  if (top == 0)
    return ct_NONE;

  return stack[top - 1];
}

/* The valid regions are 'titlepage', 'copying', and 'documentdescription'.
   This stack isn't used that much. */

static ELEMENT **region_stack;
static size_t region_top; /* One above last pushed region. */
static size_t region_space;

void
reset_region_stack (void)
{
  region_top = 0;
}

void
push_region (ELEMENT *e)
{
  if (region_top >= region_space)
    {
      region_stack = realloc (region_stack,
                              (region_space += 5) * sizeof (*region_stack));
    }

  debug (">>>>>>>>>>>>>>>>>PUSHING REGION STACK AT %d", region_top);

  region_stack[region_top++] = e;
}

ELEMENT *
pop_region ()
{
  if (region_top == 0)
    abort ();

  debug (">>>>>>>>>>>>>POPPING REGION STACK AT %d", region_top - 1);
  return region_stack[--region_top];
}

enum command_id
current_region_cmd (void)
{
  if (region_top == 0)
    return CM_NONE;

  return region_stack[region_top - 1]->cmd;
}

ELEMENT *
current_region (void)
{
  if (region_top == 0)
    return 0;

  return region_stack[region_top - 1];
}


code:
/* Copyright 2010, 2011, 2012, 2013, 2014, 2015
   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 <http://www.gnu.org/licenses/>. */

enum context {
    ct_NONE,
    ct_line,
    ct_def,
    ct_preformatted,
    ct_rawpreformatted,
    ct_menu,
    ct_math,
    ct_footnote,
    ct_caption,
    ct_shortcaption,
    ct_inlineraw
};

/* Contexts where an empty line doesn't start a new paragraph. */
/* line 492 */
#define in_paragraph_context(c) \
  !((c) == ct_math \
   || (c) == ct_menu \
   || (c) == ct_def \
   || (c) == ct_preformatted \
   || (c) == ct_rawpreformatted \
   || (c) == ct_inlineraw)

void push_context (enum context c);
enum context pop_context ();
enum context current_context (void);
void reset_context_stack (void);

void push_region (ELEMENT *r);
ELEMENT *pop_region (void);
ELEMENT *current_region (void);
enum command_id current_region_cmd (void);

void reset_region_stack (void);


code:
/* Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016
   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 <http://www.gnu.org/licenses/>. */

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

#include "parser.h"
#include "text.h"
#include "convert.h"

static void expand_cmd_args_to_texi (ELEMENT *e, TEXT *result);
static void convert_to_texinfo_internal (ELEMENT *e, TEXT *result);

#define ADD(x) text_append (result, x)

char *
node_extra_to_texi (NODE_SPEC_EXTRA *nse)
{
  TEXT result;

  if (!nse)
    return "";
  text_init (&result);

  if (nse->manual_content
      && nse->manual_content->contents.number > 0)
    {
      text_append_n (&result, "(", 1);
      convert_to_texinfo_internal (nse->manual_content, &result);
      text_append_n (&result, ")", 1);
    }
  if (nse->node_content
      && nse->node_content->contents.number > 0)
    {
      convert_to_texinfo_internal (nse->node_content, &result);
    }
  return result.text;
}

static void
expand_cmd_args_to_texi (ELEMENT *e, TEXT *result)
{
  enum command_id cmd = e->cmd;

  if (cmd)
    {
      ADD("@");  ADD(command_name(cmd));
    }

  // TODO extra spaces

  // TODO multitable or block command

  if (cmd == CM_macro || cmd == CM_rmacro)
    {
      KEY_PAIR *k;
      char *s = 0;
      k = lookup_extra_key (e, "arg_line");
      if (k)
        s = (char *)k->value;
      if (s)
        {
          ADD(s);
          return;
        }
    }

  // TODO node

  // TODO "fix" arg

  if (e->args.number > 0)
    {
      int braces, arg_nr, i;
      static char s[2];
      braces = (e->args.list[0]->type == ET_brace_command_arg
                || e->args.list[0]->type == ET_brace_command_context);
      if (braces)
        ADD("{");

      if (e->cmd == CM_verb)
        {
          s[0] = (char ) e->type;
          s[1] = '\0';
          ADD(s);
        }

      arg_nr = 0;
      for (i = 0; i < e->args.number; i++)
        {
          if (command_data(cmd).flags & CF_brace)
            {
              if (arg_nr)
                ADD(",");
              arg_nr++;
            }
          convert_to_texinfo_internal (e->args.list[i], result);
        }

      if (e->cmd == CM_verb)
        ADD(s);

      if (braces)
        ADD("}");
    }
}

static void
convert_to_texinfo_internal (ELEMENT *e, TEXT *result)
{
  if (e->text.end > 0)
    ADD(e->text.text);
  else
    {
      // TODO "fix" argument

      if (e->cmd
          || e->type == ET_def_line
          || e->type == ET_menu_entry
          || e->type == ET_menu_comment)
        {
          expand_cmd_args_to_texi (e, result);
        }

      if (e->type == ET_bracketed)
        ADD("{");
      if (e->contents.number > 0)
        {
          int i;
          for (i = 0; i < e->contents.number; i++)
            convert_to_texinfo_internal (e->contents.list[i], result);
        }
      if (e->type == ET_bracketed)
        ADD("}");

      // TODO: "fix" arg or raw block command
      if (command_flags (e) & CF_block)
        {
          ADD("@end ");
          ADD(command_name(e->cmd));
          if (command_data(e->cmd).data != BLOCK_raw)
            ADD("\n");
        }
    }

  return;
}
#undef ADD

char *
convert_to_texinfo (ELEMENT *e)
{
  TEXT result;

  if (!e)
    return "";
  text_init (&result);
  convert_to_texinfo_internal (e, &result);
  return result.text;
}

/* Very stripped-down version of Texinfo::Convert::Text.
   Convert the contents of E to plain text.  Suitable for specifying a file
   name containing an at sign or braces.  Set *SUPERFLUOUS_ARG if the contents
   of E are too complicated to convert properly. */
char *
convert_to_text (ELEMENT *e, int *superfluous_arg)
{
#define ADD(x) text_append (&result, x)

  TEXT result; int i;

  if (!e)
    return "";
  text_init (&result);
  for (i = 0; i < e->contents.number; i++)
    {
      ELEMENT *e1 = contents_child_by_index (e, i);
      if (e1->text.end > 0)
        ADD(e1->text.text);
      else if (e1->cmd == CM_AT_SIGN)
        ADD("@");
      else if (e1->cmd == CM_OPEN_BRACE)
        ADD("{");
      else if (e1->cmd == CM_CLOSE_BRACE)
        ADD("}");
      else
        *superfluous_arg = 1;
    }
  return result.text;
}
#undef ADD


code:
char *convert_to_texinfo (ELEMENT *e);
char *convert_to_text (ELEMENT *e, int *superfluous_arg);
char *node_extra_to_texi (NODE_SPEC_EXTRA *nse);


code:
#include "tree_types.h"
#include "counter.h"

void
counter_push (COUNTER *c, ELEMENT *elt, int num)
{
  if (c->nvalues >= c->space - 1)
    {
      c->space += 5;
      c->values = realloc (c->values, c->space * sizeof (int));
      c->elts = realloc (c->elts, c->space * sizeof (ELEMENT *));
      if (!c->values)
        abort ();
    }
  c->values[c->nvalues] = num;
  c->elts[c->nvalues] = elt;

  c->nvalues++;
  c->values[c->nvalues] = 0;
  c->elts[c->nvalues] = 0;
}

void
counter_pop (COUNTER *c)
{
  if (!c->nvalues)
    abort ();

  c->nvalues--;
  c->values[c->nvalues] = 0;
  c->elts[c->nvalues] = 0;
}

void
counter_inc (COUNTER *c)
{
  c->values[c->nvalues - 1]++;
}

void
counter_dec (COUNTER *c)
{
  c->values[c->nvalues - 1]--;
}

/* Return value of counter if the top counter is for element ELT, otherwise
   return -1. */
int
counter_value (COUNTER *c, ELEMENT *elt)
{
  if (c->nvalues > 0 && c->elts[c->nvalues - 1] == elt)
    return c->values[c->nvalues - 1];
  else
    return -1;
}


code:
typedef struct {
    int *values; /* Array of values. */
    ELEMENT **elts; /* Elements corresponding to each value. */
    int nvalues;
    int space;
} COUNTER;

void counter_push (COUNTER *c, ELEMENT *e, int n);
void counter_pop (COUNTER *c);
void counter_inc (COUNTER *c);
void counter_dec (COUNTER *c);
int counter_value (COUNTER *c, ELEMENT *e);


code:
/* Copyright 2014, 2015 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 <http://www.gnu.org/licenses/>. */
#include <stdarg.h>
#include <stdio.h>

/* Whether to dump debugging output on stderr. */
int debug_output = 0;

void
debug (char *s, ...)
{
  va_list v;

  if (!debug_output)
    return;
  va_start (v, s);
  vfprintf (stderr, s, v);
  fputc ('\n', stderr);
}

void
debug_nonl (char *s, ...)
{
  va_list v;

  if (!debug_output)
    return;
  va_start (v, s);
  vfprintf (stderr, s, v);
}


code:
For inspecting execution of installed makeinfo:

perl -d `which makeinfo` sample.texi

b  /usr/local/share/texinfo/Texinfo/Parser.pm:5344

p _print_tree ($current)

-----
For inspecting execution of Parsetexi module:

Uncomment DEBUG line in ./makeinfo.

b Parsetexi/lib/Parsetexi.pm:227

With _print_tree exported from Texinfo::Parser, can do

p Texinfo::Parser::_print_tree ($VAR1->{'contents'}[1])


code:
/* Copyright 2010, 2011, 2012, 2013, 2014, 2015
   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 <http://www.gnu.org/licenses/>. */

#include <string.h>

#include "parser.h"
#include "text.h"

// 1471
void
gather_def_item (ELEMENT *current, enum command_id next_command)
{
  enum element_type type;
  ELEMENT *def_item;
  int contents_count, i;

  if (next_command)
    type = ET_inter_def_item; /* Between @def*x and @def*. */
  else
    type = ET_def_item;

  if (!current->cmd)
    return;

  /* Check this isn't an "x" type command.
     "This may happen for a construct like:
     @deffnx a b @section
     but otherwise the end of line will lead to the command closing." */
  if (command_data(current->cmd).flags & CF_misc)
    return;

  def_item = new_element (type);

  /* Starting from the end, collect everything that is not a ET_def_line and
     put it into the ET_def_item. */
  contents_count = current->contents.number;
  for (i = 0; i < contents_count; i++)
    {
      ELEMENT *last_child, *item_content;
      last_child = last_contents_child (current);
      if (last_child->type == ET_def_line)
        break;
      item_content = pop_element_from_contents (current);
      insert_into_contents (def_item, item_content, 0);
    }

  if (def_item->contents.number > 0)
    add_to_element_contents (current, def_item);
  else
    destroy_element (def_item);
}

static void
shallow_destroy_element (ELEMENT *e)
{
  free (e->text.text);
  free (e);
}

// 2335
/* Used for definition line parsing.  Return next unit on the line after
   a definition command like @deffn.  The contents of E is what is remaining
   in the argument line.  *SPACES_OUT is set to an element with spaces before
   the line. */
static ELEMENT *
next_bracketed_or_word (ELEMENT *e, ELEMENT **spaces_out, int join)
{
  char *text;
  ELEMENT *spaces = 0;
  int space_len = 0;
  ELEMENT *ret;
  ELEMENT *f;

  *spaces_out = 0;
  if (e->contents.number == 0)
    return 0; /* No more arguments */

  f = e->contents.list[0];
  text = f->text.text;
  if (text)
    space_len = strspn (text, whitespace_chars);
  if (space_len)
    {
      /* Remove a trailing newline. */
      if (text[space_len - 1] == '\n')
        {
          text[--space_len] == '\0';
          f->text.end--;
        }

      if (space_len)
        {
          spaces = new_element (ET_spaces);
          spaces->parent_type = route_not_in_tree;
          text_append_n (&spaces->text, text, space_len);
          memmove (f->text.text,
                   f->text.text + space_len,
                   f->text.end - space_len + 1);
          f->text.end -= space_len;
        }

      if (f->text.end == 0)
        {
          (void ) remove_from_contents (e, 0);
          shallow_destroy_element (f);
        }
      *spaces_out = spaces;
    }

  if (e->contents.number == 0)
    return 0; /* No more arguments */

  ret = new_element (ET_NONE);
  ret->parent_type = route_not_in_tree;
  while (e->contents.number > 0)
    {
      f = e->contents.list[0];
      if (f->type == ET_bracketed)
        {
          (void) remove_from_contents (e, 0);
          f->type = ET_bracketed_def_content;
          isolate_last_space (f, 0);
          add_to_contents_as_array (ret, f);
          if (!join)
            break;
        }
      else if (f->cmd) // 2363
        {
          (void ) remove_from_contents (e, 0);
          add_to_contents_as_array (ret, f);
          if (!join)
            break;
        }
      else
        {
          /* Extract span of non-whitespace characters. */
          ELEMENT *returned;
          int arg_len;

          text = f->text.text;
          if (!*text)
            {
              /* Finished with this element */
              remove_from_contents (e, 0);
              shallow_destroy_element (f);
              continue;
            }

          space_len = strspn (text, whitespace_chars);
          if (space_len > 0)
            break; /* Finished */

          returned = new_element (ET_NONE);
          returned->parent_type = route_not_in_tree;
          arg_len = strcspn (text, whitespace_chars);
          text_append_n (&returned->text, text, arg_len);
          memmove (f->text.text, f->text.text + space_len + arg_len,
                   f->text.end - (space_len + arg_len) + 1);
          f->text.end -= space_len + arg_len;

          add_to_contents_as_array (ret, returned);
          if (!join)
            break;
       }
    }
  if (ret->contents.number == 1)
    {
      ELEMENT *tmp = ret;
      ret = ret->contents.list[0];
      shallow_destroy_element (tmp);
    }
  else if (ret->contents.number == 0)
    abort ();

  return ret;
}

typedef struct {
    enum command_id alias;
    enum command_id command;
    char *category;
} DEF_ALIAS;

DEF_ALIAS def_aliases[] = {
  CM_defun, CM_deffn, "Function",
  CM_defmac, CM_deffn, "Macro",
  CM_defspec, CM_deffn, "Special Form",
  CM_defvar, CM_defvr, "Variable",
  CM_defopt, CM_defvr, "User Option",
  CM_deftypefun, CM_deftypefn, "Function",
  CM_deftypevar, CM_deftypevr, "Variable",
  CM_defivar, CM_defcv, "Instance Variable",
  CM_deftypeivar, CM_deftypecv, "Instance Variable",
  CM_defmethod, CM_defop, "Method",
  CM_deftypemethod, CM_deftypeop, "Method",
  0, 0, 0
};

static void
add_to_def_args_extra (DEF_ARGS_EXTRA *d, char *label, ELEMENT *arg)
{
  if (d->nelements >= d->space - 1)
    {
      d->space += 5;
      d->labels = realloc (d->labels, d->space * sizeof (char *));
      d->elements = realloc (d->elements, d->space * sizeof (ELEMENT *));
    }

  if (arg && arg->hv)
    abort ();
  if (!arg)
    return; /* Probably a bug */

  d->labels[d->nelements] = label;
  d->elements[d->nelements++] = arg;
  d->labels[d->nelements] = 0;
  d->elements[d->nelements] = 0;
}

/* Parse the arguments on a def* command line. */
// 2378
DEF_ARGS_EXTRA *
parse_def (enum command_id command, ELEMENT_LIST contents)
{
  /* The return value - suitable for "def_args" extra value. */
  DEF_ARGS_EXTRA *def_args;
  int i, args_start = 0;

  ELEMENT *arg_line; /* Copy of argument line. */
  ELEMENT *arg, *spaces; /* Arguments and spaces extracted from line. */
  ELEMENT *e, *e1;

  enum command_id original_command = CM_NONE;

  def_args = malloc (sizeof (DEF_ARGS_EXTRA));
  memset (def_args, 0, sizeof (DEF_ARGS_EXTRA));

  /* Copy contents of argument line. */
  arg_line = new_element (ET_NONE);
  for (i = contents.list[0]->type != ET_empty_spaces_after_command ? 0 : 1;
       i < contents.number; i++)
    {
      if (contents.list[i]->text.space > 0)
        {
          /* Copy text to avoid changing the original. */
          ELEMENT *copy = new_element (ET_NONE);
          copy->parent_type = route_not_in_tree;
          copy->parent = 0;
          text_init (&copy->text);
          text_append_n (&copy->text,
                         contents.list[i]->text.text,
                         contents.list[i]->text.end);
          add_to_contents_as_array (arg_line, copy);

          /* Note that these copied elements should be destroyed with
             shallow_destroy_element, not destroy_element, because their
             contents and args are shared with in-tree elements. */
        }
      else
        {
          add_to_contents_as_array (arg_line, contents.list[i]);
        }
    }

  if (arg_line->contents.number > 0 // 2385
      && arg_line->contents.list[0]->type == ET_empty_spaces_after_command)
    {
      remove_from_contents (arg_line, 0);
    }

  /* Check for "def alias" - for example @defun for @deffn. */
  if (command_data(command).flags & CF_def_alias) // 2387
    {
      char *category;
      int i;
      for (i = 0; i < sizeof (def_aliases) / sizeof (*def_aliases); i++)
        {
          if (def_aliases[i].alias == command)
            goto found;
        }
      abort (); /* Has CF_def_alias but no alias defined. */
found:
      /* Prepended content is stuck into contents, so
         @defun is converted into
         @deffn Function */

      category = def_aliases[i].category;
      original_command = command;
      command = def_aliases[i].command;

      /* Used when category text has a space in it. */
      e = new_element (ET_bracketed);
      insert_into_contents (arg_line, e, 0);
      e->parent = 0;
      e->parent_type = route_not_in_tree;
      e1 = new_element (ET_NONE);
      text_append_n (&e1->text, category, strlen (category));
      add_to_element_contents (e, e1);
      if (global_documentlanguage && *global_documentlanguage)
        {
          e1->type = ET_untranslated;
          add_extra_string (e1, "documentlanguage",
                            global_documentlanguage);
        }
      e1->parent_type = route_not_in_tree;

      e = new_element (ET_NONE);
      text_append_n (&e->text, " ", 1);
      insert_into_contents (arg_line, e, 1);
      e->parent_type = route_not_in_tree;
    }

  /* Read arguments as CATEGORY [CLASS] [TYPE] NAME [ARGUMENTS].

     Meaning of these:
     CATEGORY - type of entity, e.g. "Function"
     CLASS - class for object-oriented programming
     TYPE - data type of a variable or function return value
     NAME - name of entity being documented
     ARGUMENTS - arguments to a function or macro                  */

  /* CATEGORY */
  arg = next_bracketed_or_word (arg_line, &spaces, 1);
  if (!arg)
    goto finished;
  if (spaces)
    add_to_def_args_extra (def_args, "spaces", spaces);
  add_to_def_args_extra (def_args, "category", arg);

  /* CLASS */
  if (command == CM_deftypeop
      || command == CM_defcv
      || command == CM_deftypecv
      || command == CM_defop)
    {
      arg = next_bracketed_or_word (arg_line, &spaces, 1);
      if (spaces)
        add_to_def_args_extra (def_args, "spaces", spaces);
      if (!arg)
        goto finished;
      add_to_def_args_extra (def_args, "class", arg);
    }

  /* TYPE */
  if (command == CM_deftypefn
      || command == CM_deftypeop
      || command == CM_deftypevr
      || command == CM_deftypecv)
    {
      arg = next_bracketed_or_word (arg_line, &spaces, 1);
      if (spaces)
        add_to_def_args_extra (def_args, "spaces", spaces);
      if (!arg)
        goto finished;
      add_to_def_args_extra (def_args, "type", arg);
    }

  /* NAME */
  /* All command types get a name. */
  arg = next_bracketed_or_word (arg_line, &spaces, 1);
  if (spaces)
    add_to_def_args_extra (def_args, "spaces", spaces);
  if (!arg)
    goto finished;
  add_to_def_args_extra (def_args, "name", arg);

  /* ARGUMENTS */

  args_start = def_args->nelements;
  // 2441
  while (arg_line->contents.number > 0)
    {
      arg = next_bracketed_or_word (arg_line, &spaces, 0);
      if (spaces)
        add_to_def_args_extra (def_args, "spaces", spaces);
      if (!arg)
        goto finished;
      if (arg->text.end > 0) // 2445
        {
          ELEMENT *e;
          char *p = arg->text.text;
          int len;
          /* Split this argument into multiple arguments, separated by
             separator characters. */
          while (1)
            {
              /* Square and round brackets used for optional arguments
                 and grouping.  Commas allowed as well? */
              len = strcspn (p, "[](),");
              if (len > 0)
                {
                  e = new_element (ET_NONE);
                  e->parent_type = route_not_in_tree;
                  text_append_n (&e->text, p, len);
                  add_to_def_args_extra (def_args, "arg", e);
                  p += len;
                }
              if (!*p)
                break;
              while (*p && strchr ("[](),", *p))
                {
                  e = new_element (ET_delimiter);
                  e->parent_type = route_not_in_tree;
                  text_append_n (&e->text, p++, 1);
                  add_to_def_args_extra (def_args, "delimiter", e);
                }
              if (!*p)
                break;
            }
          destroy_element (arg);
        }
      else
        {
          add_to_def_args_extra (def_args, "arg", arg);
        }
    }

finished:

  // 2460 - argtype
  /* Change some of the left sides to 'typearg'.  This matters for
     the DocBook output. */
  if (args_start > 0
      && (command == CM_deftypefn || command == CM_deftypeop
          || command == CM_deftp))
    {
      int i, next_is_type = 1;
      for (i = args_start; i < def_args->nelements; i++)
        {
          if (!strcmp ("spaces", def_args->labels[i]))
            {
            }
          else if (!strcmp ("delimiter", def_args->labels[i]))
            {
              next_is_type = 1;
            }
          else if (def_args->elements[i]->cmd
                   && def_args->elements[i]->cmd != CM_code)
            {
              next_is_type = 1;
            }
          else if (next_is_type)
            {
              def_args->labels[i] = "typearg";
              next_is_type = 0;
            }
          else
            next_is_type = 1;
        }
    }

  destroy_element (arg_line);
  return def_args;
}


code:
void gather_def_item (ELEMENT *current, enum command_id next_command);
DEF_ARGS_EXTRA *parse_def (enum command_id command, ELEMENT_LIST contents);