1#! /usr/local/bin/gawk -f
2
3# prepinfo.awk --- fix node lines and menus
4#
5# Copyright, 1998, Arnold Robbins, arnold@gnu.org
6#
7# PREPINFO is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11# 
12# PREPINFO is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16# 
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20
21BEGIN	\
22{
23	# manifest constants
24	TRUE = 1
25	FALSE = 0
26
27	# Levels at which different nodes can be
28	Level["@top"] =	0
29	Level["@appendix"] = 1
30	Level["@chapter"] = 1
31	Level["@majorheading"] = 1
32	Level["@unnumbered"] = 1
33	Level["@appendixsec"] = 2
34	Level["@heading"] = 2
35	Level["@section"] = 2
36	Level["@unnumberedsec"] = 2
37	Level["@unnumberedsubsec"] = 3
38	Level["@appendixsubsec"] = 3
39	Level["@subheading"] = 3
40	Level["@subsection"] = 3
41	Level["@appendixsubsubsec"] = 4
42	Level["@subsubheading"] = 4
43	Level["@subsubsection"] = 4
44	Level["@unnumberedsubsubsec"] = 4
45
46	# Length of menus
47	Menumargin = 78
48
49	# Length of menu item
50	Min_menitem_length = 29
51
52	# insure that we were called correctly
53	if (ARGC != 2) {
54		printf("usage: %s texinfo-file\n", ARGV[0]) > "/dev/stderr"
55		exit 1
56	}
57
58	# Arrange for two passes over input file
59	Pass = 1
60	ARGV[2] = "Pass=2"
61	ARGV[3] = ARGV[1]
62	ARGC = 4
63	Lastlevel = -1
64
65	# Initialize stacks
66	Up[-1] = "(dir)"
67	Prev[0] = "(dir)"
68
69	if (Debug == "args") {
70		for (i = 0; i < ARGC; i++)
71			printf("ARGV[%d] = %s\n", i, ARGV[i]) > "/dev/stderr"
72	}
73}
74
75$1 == "@node"	\
76{
77	Name = getnodename($0)
78	Nodeseen = TRUE
79
80	if ((l = length(Name)) > Maxlen)
81		Maxlen = l
82
83	if (Debug == "nodenames")
84		printf("Name = %s\n", Name) > "/dev/stderr"
85
86	if (Pass == 1)
87		next
88}
89
90Pass == 1 && /^@c(omment)?[ \t]+fakenode/ \
91{
92	if (Debug == "fakenodes")
93		printf("fakenode at %d\n", FNR) > "/dev/stderr"
94	Fakenode = TRUE
95	next
96}
97
98Pass == 1 && ($1 in Level)	\
99{
100	# skip fake nodes --- titles without associated @node lines
101	if (Fakenode) {
102		if (Debug == "fakenodes")
103			printf("%s at %d is a fakenode\n", $1, FNR) > "/dev/stderr"
104		Fakenode = FALSE
105		next
106	}
107
108	if (Debug == "titles")
109		printf("Processing %s: Name = %s\n", $1, Name) > "/dev/stderr"
110
111	# save type
112	type = $1
113
114	if (! Nodeseen) {
115		err_prefix()
116		printf("%s line with no @node or fakenode line\n",
117			type) > "/dev/stderr"
118		Badheading[FNR] = 1
119		# ??? used ???
120		next
121	} else
122		Nodeseen = FALSE	# reset it
123
124	# Squirrel away the info
125	levelnum = Level[type]
126	Node[Name ".level"] = levelnum
127	Node[Name ".name"] = Name
128	if (Debug == "titles") {
129		printf("Node[%s\".level\"] = %s\n", Name, Node[Name ".level"]) > "/dev/stderr"
130		printf("Node[%s\".name\"] = %s\n", Name, Node[Name ".name"]) > "/dev/stderr"
131	}
132
133	if (levelnum == Lastlevel) {	# e.g., two sections in a row
134		Node[Name ".up"] = Up[levelnum - 1]
135		if (levelnum in Prev) {
136			Node[Prev[levelnum] ".next"] = Name
137			Node[Name ".prev"] = Prev[levelnum]
138		}
139		Prev[levelnum] = Name
140		Up[levelnum] = Name	# ???
141	} else if (levelnum < Lastlevel) {	# section, now chapter
142		Lastlevel = levelnum
143		Node[Name ".up"] = Up[levelnum - 1]
144		if (levelnum in Prev) {
145			Node[Name ".prev"] = Prev[levelnum]
146			Node[Prev[levelnum] ".next"] = Name
147		}
148		Prev[levelnum] = Name
149		Up[levelnum] = Name
150	} else {		# chapter, now section, levelnum > Lastlevel
151		Node[Name ".up"] = Up[levelnum - 1]
152		Node[Up[Lastlevel] ".child"] = Name
153		Up[levelnum] = Name
154		Prev[levelnum] = Name
155		Lastlevel = levelnum
156	}
157
158	# For master menu
159	if (Level[$1] >= 2)
160		List[++Sequence] = Name
161
162	if (Debug == "titles") {
163		printf("Node[%s\".prev\"] = %s\n", Name, Node[Name ".prev"]) > "/dev/stderr"
164		printf("Node[%s\".up\"] = %s\n", Name, Node[Name ".up"]) > "/dev/stderr"
165		printf("Node[%s\".child\"] = %s\n", Name, Node[Name ".child"]) > "/dev/stderr"
166	}
167}
168
169Pass == 2 && Debug == "dumptitles" && FNR <= 1	\
170{
171	for (i in Node)
172		printf("Node[%s] = %s\n", i, Node[i]) | "sort 1>&2"
173	close("sort 1>&2")
174}
175
176/^@menu/ && Pass == 1, /^@end[ \t]+menu/ && Pass == 1	\
177{
178	if (/^@menu/ || /^@end[ \t]+menu/)
179		next
180
181#	if (Debug == "menu")
182#		printf("processing: %s\n", $0) > "/dev/stderr"
183
184	if (/^\*/) {
185		if (In_menitem) {	# file away info from previousline
186			Node[node ".mendesc"] = desc
187			Node[node ".longdesc"] = longdesc
188			if (Debug == "mendesc") {
189				printf("Node[%s.mendesc] = %s\n",
190					node, Node[node ".mendesc"]) > "/dev/stderr"
191				printf("Node[%s.longdesc] = %s\n",
192					node, Node[node ".longdesc"]) > "/dev/stderr"
193			}
194		}
195		In_menitem = TRUE
196
197		# pull apart menu item
198		$1 = ""		# nuke ``*''
199		$0 = $0		# reparse line
200		i1 = index($0, ":")
201		if (i1 <= 0) {
202			err_prefix()
203			printf("badly formed menu item") > "/dev/stderr"
204			next
205		}
206		if (substr($0, i1+1, 1) != ":") { # desc: node.  long desc
207			i2 = index($0, ".")
208			if (i2 <= 0) {
209				err_prefix()
210				printf("badly formed menu item") > "/dev/stderr"
211				next
212			}
213			desc = substr($0, 1, i1 - 1)
214			sub(/^[ \t]+/, "", node)
215			sub(/[ \t]+$/, "", node)
216			longdesc = substr($0, i2 + 1)
217		} else {	# nodname:: long desc
218			desc = ""
219			node = substr($0, 1, i1 - 1)
220			sub(/^[ \t]+/, "", node)
221			sub(/[ \t]+$/, "", node)
222			longdesc = substr($0, i1 + 2)
223		}
224	} else if (In_menitem) {	# continuation line
225		longdesc = longdesc " " $0
226	} else
227		In_menitem = FALSE
228
229	Node[node ".mendesc"] = desc
230	Node[node ".longdesc"] = longdesc
231	if (Debug == "mendesc") {
232		printf("Node[%s.mendesc] = %s\n",
233			node, Node[node ".mendesc"]) > "/dev/stderr"
234		printf("Node[%s.longdesc] = %s\n",
235			node, Node[node ".longdesc"]) > "/dev/stderr"
236	}
237
238	if (Debug == "menu")
239		printf("Menu:: Name %s: desc %s: longdesc %s\n",
240			node, desc, longdesc) > "/dev/stderr"
241}
242
243function err_prefix()
244{
245	printf("%s: %s: %d: ", ARGV[0], FILENAME, FNR) > "/dev/stderr"
246}
247
248function getnodename(str)
249{
250	sub(/@node[ \t]+/, "", str)
251	sub(/,.*/, "", str)
252	if (Debug == "nodenames")
253		printf("getnodename: return %s\n", str) > "/dev/stderr"
254	return str
255}
256
257Pass == 2 && /^@node/	\
258{
259	Name = getnodename($0)
260
261	# Top node is special. It's next is the first child
262	n = Node[Name ".next"]
263	if (Node[Name ".level"] == 0 && n == "")
264		n = Node[Name ".child"]
265
266	printf("@node %s, %s, %s, %s\n", Name, n,
267		Node[Name ".prev"] ? Node[Name ".prev"] : Node[Name ".up"],
268		Node[Name ".up"])
269	next
270}
271
272Pass == 2 && /^@menu/	\
273{
274	# First, nuke current contents of menu
275	do {
276		if ((getline) <= 0) {
277			err_prefix()
278			printf("unexpected EOF inside menu\n") > "/dev/stderr"
279			exit 1
280		}
281	} while (! /^@end[ \t]+menu/)
282
283	# next, compute maximum length of a node name
284	max = 0
285	for (n = Node[Name ".child"]; (n ".next") in Node; n = Node[n ".next"]) {
286		if ((n ".desc") in Node)
287			s = Node[n ".desc"] ": " n "."
288		else
289			s = n "::"
290		l = length(s)
291		if (l > max)
292			max = l
293	}
294	if (max < Min_menitem_length)
295		max = Min_menitem_length
296
297	# now dump the menu
298	print "@menu"
299
300	for (n = Node[Name ".child"]; (n ".next") in Node; n = Node[n ".next"]) {
301		print_menuitem(n, max)
302	}
303	print_menuitem(n, max)
304
305	if (Name == "Top") {	# Master Menu
306		if (Maxlen < Min_menitem_length)
307			Maxlen = Min_menitem_length
308		print ""
309		for (i = 1; i <= Sequence; i++)
310			print_menuitem(List[i], Maxlen)
311		print ""
312	}
313	print "@end menu"
314	next
315}
316
317Pass == 2	# print
318
319
320function print_menuitem(n, max,		nodesc, i, dwords, count, p)
321{
322	nodesc = FALSE
323	if (! ((n ".longdesc") in Node)) {
324		err_prefix()
325		printf("warning: %s: no long description\n", n) > "/dev/stderr"
326		nodesc = TRUE
327	} else {
328		for (i in dwords)
329			delete dwords[i]
330		count = split(Node[n ".longdesc"], dwords, "[ \t\n]+")
331	}
332	if ((n ".desc") in Node)
333		s = Node[n ".desc"] ": " n "."
334	else
335		s = n "::"
336	printf("* %-*s", max, s)
337
338	if (Debug == "mendescitem")
339		printf("<* %-*s>\n", max, s) > "/dev/stderr"
340
341	p = max + 2
342	if (! nodesc) {
343		for (i = 1; i <= count; i++) {
344			l = length(dwords[i])
345			if (l == 0)
346				continue
347			if (p + l + 1 > Menumargin) {
348				printf("\n%*s", max + 2, " ")
349				p = max + 2
350			}
351			printf(" %s", dwords[i])
352			p += l + 1
353		}
354	}
355	print ""
356}
357