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

# prepinfo.awk --- fix node lines and menus
#
# Copyright 1998 Arnold Robbins
#
# 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 3 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, see <http://www.gnu.org/licenses/>.

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 ""
}
