#! /usr/local/bin/gawk -f

# prepinfo.awk --- fix node lines and menus
#
# Copyright, 1998, Arnold Robbins, [email protected]
#
# PREPINFO 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 of the License, or
# (at your option) any later version.
#
# PREPINFO is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

BEGIN   \
{
       # manifest constants
       TRUE = 1
       FALSE = 0

       # Levels at which different nodes can be
       Level["@top"] = 0
       Level["@appendix"] = 1
       Level["@chapter"] = 1
       Level["@majorheading"] = 1
       Level["@unnumbered"] = 1
       Level["@appendixsec"] = 2
       Level["@heading"] = 2
       Level["@section"] = 2
       Level["@unnumberedsec"] = 2
       Level["@unnumberedsubsec"] = 3
       Level["@appendixsubsec"] = 3
       Level["@subheading"] = 3
       Level["@subsection"] = 3
       Level["@appendixsubsubsec"] = 4
       Level["@subsubheading"] = 4
       Level["@subsubsection"] = 4
       Level["@unnumberedsubsubsec"] = 4

       # Length of menus
       Menumargin = 78

       # Length of menu item
       Min_menitem_length = 29

       # insure that we were called correctly
       if (ARGC != 2) {
               printf("usage: %s texinfo-file\n", ARGV[0]) > "/dev/stderr"
               exit 1
       }

       # Arrange for two passes over input file
       Pass = 1
       ARGV[2] = "Pass=2"
       ARGV[3] = ARGV[1]
       ARGC = 4
       Lastlevel = -1

       # Initialize stacks
       Up[-1] = "(dir)"
       Prev[0] = "(dir)"

       if (Debug == "args") {
               for (i = 0; i < ARGC; i++)
                       printf("ARGV[%d] = %s\n", i, ARGV[i]) > "/dev/stderr"
       }
}

$1 == "@node"   \
{
       Name = getnodename($0)
       Nodeseen = TRUE

       if ((l = length(Name)) > Maxlen)
               Maxlen = l

       if (Debug == "nodenames")
               printf("Name = %s\n", Name) > "/dev/stderr"

       if (Pass == 1)
               next
}

Pass == 1 && /^@c(omment)?[ \t]+fakenode/ \
{
       if (Debug == "fakenodes")
               printf("fakenode at %d\n", FNR) > "/dev/stderr"
       Fakenode = TRUE
       next
}

Pass == 1 && ($1 in Level)      \
{
       # skip fake nodes --- titles without associated @node lines
       if (Fakenode) {
               if (Debug == "fakenodes")
                       printf("%s at %d is a fakenode\n", $1, FNR) > "/dev/stderr"
               Fakenode = FALSE
               next
       }

       if (Debug == "titles")
               printf("Processing %s: Name = %s\n", $1, Name) > "/dev/stderr"

       # save type
       type = $1

       if (! Nodeseen) {
               err_prefix()
               printf("%s line with no @node or fakenode line\n",
                       type) > "/dev/stderr"
               Badheading[FNR] = 1
               # ??? used ???
               next
       } else
               Nodeseen = FALSE        # reset it

       # Squirrel away the info
       levelnum = Level[type]
       Node[Name ".level"] = levelnum
       Node[Name ".name"] = Name
       if (Debug == "titles") {
               printf("Node[%s\".level\"] = %s\n", Name, Node[Name ".level"]) > "/dev/stderr"
               printf("Node[%s\".name\"] = %s\n", Name, Node[Name ".name"]) > "/dev/stderr"
       }

       if (levelnum == Lastlevel) {    # e.g., two sections in a row
               Node[Name ".up"] = Up[levelnum - 1]
               if (levelnum in Prev) {
                       Node[Prev[levelnum] ".next"] = Name
                       Node[Name ".prev"] = Prev[levelnum]
               }
               Prev[levelnum] = Name
               Up[levelnum] = Name     # ???
       } else if (levelnum < Lastlevel) {      # section, now chapter
               Lastlevel = levelnum
               Node[Name ".up"] = Up[levelnum - 1]
               if (levelnum in Prev) {
                       Node[Name ".prev"] = Prev[levelnum]
                       Node[Prev[levelnum] ".next"] = Name
               }
               Prev[levelnum] = Name
               Up[levelnum] = Name
       } else {                # chapter, now section, levelnum > Lastlevel
               Node[Name ".up"] = Up[levelnum - 1]
               Node[Up[Lastlevel] ".child"] = Name
               Up[levelnum] = Name
               Prev[levelnum] = Name
               Lastlevel = levelnum
       }

       # For master menu
       if (Level[$1] >= 2)
               List[++Sequence] = Name

       if (Debug == "titles") {
               printf("Node[%s\".prev\"] = %s\n", Name, Node[Name ".prev"]) > "/dev/stderr"
               printf("Node[%s\".up\"] = %s\n", Name, Node[Name ".up"]) > "/dev/stderr"
               printf("Node[%s\".child\"] = %s\n", Name, Node[Name ".child"]) > "/dev/stderr"
       }
}

Pass == 2 && Debug == "dumptitles" && FNR <= 1  \
{
       for (i in Node)
               printf("Node[%s] = %s\n", i, Node[i]) | "sort 1>&2"
       close("sort 1>&2")
}

/^@menu/ && Pass == 1, /^@end[ \t]+menu/ && Pass == 1   \
{
       if (/^@menu/ || /^@end[ \t]+menu/)
               next

#       if (Debug == "menu")
#               printf("processing: %s\n", $0) > "/dev/stderr"

       if (/^\*/) {
               if (In_menitem) {       # file away info from previousline
                       Node[node ".mendesc"] = desc
                       Node[node ".longdesc"] = longdesc
                       if (Debug == "mendesc") {
                               printf("Node[%s.mendesc] = %s\n",
                                       node, Node[node ".mendesc"]) > "/dev/stderr"
                               printf("Node[%s.longdesc] = %s\n",
                                       node, Node[node ".longdesc"]) > "/dev/stderr"
                       }
               }
               In_menitem = TRUE

               # pull apart menu item
               $1 = ""         # nuke ``*''
               $0 = $0         # reparse line
               i1 = index($0, ":")
               if (i1 <= 0) {
                       err_prefix()
                       printf("badly formed menu item") > "/dev/stderr"
                       next
               }
               if (substr($0, i1+1, 1) != ":") { # desc: node.  long desc
                       i2 = index($0, ".")
                       if (i2 <= 0) {
                               err_prefix()
                               printf("badly formed menu item") > "/dev/stderr"
                               next
                       }
                       desc = substr($0, 1, i1 - 1)
                       sub(/^[ \t]+/, "", node)
                       sub(/[ \t]+$/, "", node)
                       longdesc = substr($0, i2 + 1)
               } else {        # nodname:: long desc
                       desc = ""
                       node = substr($0, 1, i1 - 1)
                       sub(/^[ \t]+/, "", node)
                       sub(/[ \t]+$/, "", node)
                       longdesc = substr($0, i1 + 2)
               }
       } else if (In_menitem) {        # continuation line
               longdesc = longdesc " " $0
       } else
               In_menitem = FALSE

       Node[node ".mendesc"] = desc
       Node[node ".longdesc"] = longdesc
       if (Debug == "mendesc") {
               printf("Node[%s.mendesc] = %s\n",
                       node, Node[node ".mendesc"]) > "/dev/stderr"
               printf("Node[%s.longdesc] = %s\n",
                       node, Node[node ".longdesc"]) > "/dev/stderr"
       }

       if (Debug == "menu")
               printf("Menu:: Name %s: desc %s: longdesc %s\n",
                       node, desc, longdesc) > "/dev/stderr"
}

function err_prefix()
{
       printf("%s: %s: %d: ", ARGV[0], FILENAME, FNR) > "/dev/stderr"
}

function getnodename(str)
{
       sub(/@node[ \t]+/, "", str)
       sub(/,.*/, "", str)
       if (Debug == "nodenames")
               printf("getnodename: return %s\n", str) > "/dev/stderr"
       return str
}

Pass == 2 && /^@node/   \
{
       Name = getnodename($0)

       # Top node is special. It's next is the first child
       n = Node[Name ".next"]
       if (Node[Name ".level"] == 0 && n == "")
               n = Node[Name ".child"]

       printf("@node %s, %s, %s, %s\n", Name, n,
               Node[Name ".prev"] ? Node[Name ".prev"] : Node[Name ".up"],
               Node[Name ".up"])
       next
}

Pass == 2 && /^@menu/   \
{
       # First, nuke current contents of menu
       do {
               if ((getline) <= 0) {
                       err_prefix()
                       printf("unexpected EOF inside menu\n") > "/dev/stderr"
                       exit 1
               }
       } while (! /^@end[ \t]+menu/)

       # next, compute maximum length of a node name
       max = 0
       for (n = Node[Name ".child"]; (n ".next") in Node; n = Node[n ".next"]) {
               if ((n ".desc") in Node)
                       s = Node[n ".desc"] ": " n "."
               else
                       s = n "::"
               l = length(s)
               if (l > max)
                       max = l
       }
       if (max < Min_menitem_length)
               max = Min_menitem_length

       # now dump the menu
       print "@menu"

       for (n = Node[Name ".child"]; (n ".next") in Node; n = Node[n ".next"]) {
               print_menuitem(n, max)
       }
       print_menuitem(n, max)

       if (Name == "Top") {    # Master Menu
               if (Maxlen < Min_menitem_length)
                       Maxlen = Min_menitem_length
               print ""
               for (i = 1; i <= Sequence; i++)
                       print_menuitem(List[i], Maxlen)
               print ""
       }
       print "@end menu"
       next
}

Pass == 2       # print


function print_menuitem(n, max,         nodesc, i, dwords, count, p)
{
       nodesc = FALSE
       if (! ((n ".longdesc") in Node)) {
               err_prefix()
               printf("warning: %s: no long description\n", n) > "/dev/stderr"
               nodesc = TRUE
       } else {
               for (i in dwords)
                       delete dwords[i]
               count = split(Node[n ".longdesc"], dwords, "[ \t\n]+")
       }
       if ((n ".desc") in Node)
               s = Node[n ".desc"] ": " n "."
       else
               s = n "::"
       printf("* %-*s", max, s)

       if (Debug == "mendescitem")
               printf("<* %-*s>\n", max, s) > "/dev/stderr"

       p = max + 2
       if (! nodesc) {
               for (i = 1; i <= count; i++) {
                       l = length(dwords[i])
                       if (l == 0)
                               continue
                       if (p + l + 1 > Menumargin) {
                               printf("\n%*s", max + 2, " ")
                               p = max + 2
                       }
                       printf(" %s", dwords[i])
                       p += l + 1
               }
       }
       print ""
}