1238438Sdteske#!/bin/sh
2238438Sdteske#-
3249746Sdteske# Copyright (c) 2012-2013 Devin Teske
4252980Sdteske# All rights reserved.
5238438Sdteske#
6238438Sdteske# Redistribution and use in source and binary forms, with or without
7238438Sdteske# modification, are permitted provided that the following conditions
8238438Sdteske# are met:
9238438Sdteske# 1. Redistributions of source code must retain the above copyright
10238438Sdteske#    notice, this list of conditions and the following disclaimer.
11238438Sdteske# 2. Redistributions in binary form must reproduce the above copyright
12238438Sdteske#    notice, this list of conditions and the following disclaimer in the
13238438Sdteske#    documentation and/or other materials provided with the distribution.
14238438Sdteske#
15238438Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16252987Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17238438Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18238438Sdteske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19238438Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20252987Sdteske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21238438Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22238438Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23238438Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24238438Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25238438Sdteske# SUCH DAMAGE.
26238438Sdteske#
27238438Sdteske# $FreeBSD$
28238438Sdteske#
29238438Sdteske############################################################ INCLUDES
30238438Sdteske
31249746Sdteske# Prevent common.subr from auto initializing debugging (this is not an inter-
32266290Sdteske# active utility so does not require debugging; also `-d' has been repurposed).
33249746Sdteske#
34249746SdteskeDEBUG_SELF_INITIALIZE=NO
35249746Sdteske
36240684SdteskeBSDCFG_SHARE="/usr/share/bsdconfig"
37240684Sdteske. $BSDCFG_SHARE/common.subr || exit 1
38244675Sdteskef_dprintf "%s: loading includes..." "$0"
39240684Sdteske
40240684SdteskeBSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="dot"
41238438Sdteskef_include_lang $BSDCFG_LIBE/include/messages.subr
42238438Sdteskef_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
43238438Sdteske
44260678Sdteskef_index_menusel_keyword $BSDCFG_LIBE/$APP_DIR/INDEX "$pgm" ipgm &&
45260678Sdteske	pgm="${ipgm:-$pgm}"
46238438Sdteske
47238438Sdteske############################################################ CONFIGURATION
48238438Sdteske
49238438Sdteske#
50251909Sdteske# Location of bsdconfig(8)
51238438Sdteske#
52238438SdteskeBSDCONFIG=/usr/sbin/bsdconfig
53238438Sdteske
54238438Sdteske############################################################ GLOBALS
55238438Sdteske
56238438Sdteske#
57238438Sdteske# Options
58238438Sdteske#
59238438SdteskeSHOW_GRAPH_LABEL_DATE=1
60238438SdteskeSHOW_INCLUDES=1
61238438SdteskeSHOW_CMDLINE=1
62238438Sdteske
63238438Sdteske############################################################ FUNCTIONS
64238438Sdteske
65238438Sdteske# begin_nodelist $shape $color $fillcolor $style
66238438Sdteske#
67238438Sdteske# Create a new multi-node list rendering nodes in a specific style described by
68238438Sdteske# the arguments passed.
69238438Sdteske#
70238438Sdteskebegin_nodelist()
71238438Sdteske{
72238438Sdteske	local shape="$1" color="$2" fillcolor="$3" style="$4"
73238438Sdteske
74238438Sdteske	printf "\tnode [\n"
75238438Sdteske	[ "$shape" ] &&
76238438Sdteske		printf '\t\tshape = "%s",\n' "$shape"
77238438Sdteske	[ "$color" ] &&
78238438Sdteske		printf '\t\tcolor = "%s",\n' "$color"
79238438Sdteske	[ "$fillcolor" ] &&
80238438Sdteske		printf '\t\tfillcolor = "%s",\n' "$fillcolor"
81238438Sdteske	[ "$style" ] &&
82238438Sdteske		printf '\t\tstyle = "%s",\n' "$style"
83238438Sdteske	printf "\t] {\n"
84238438Sdteske}
85238438Sdteske
86238438Sdteske# print_node $node [$attributes ...]
87238438Sdteske#
88238438Sdteske# Print a node within a multi-node list.
89238438Sdteske#
90238438Sdteskeprint_node()
91238438Sdteske{
92238438Sdteske	local node="$1"
93238438Sdteske
94238438Sdteske	shift 1 # node
95238438Sdteske
96238438Sdteske	case "$node" in
97252178Sdteske	edge) printf '\t\t%s' "$node" ;;
98252178Sdteske	   *) printf '\t\t"%s"' "$node" ;;
99238438Sdteske	esac
100238438Sdteske
101238438Sdteske	if [ $# -gt 0 ]; then
102238438Sdteske		echo -n ' ['
103238438Sdteske		while [ $# -gt 0 ]; do
104238438Sdteske			printf " %s" "$1"
105238438Sdteske			shift 1
106238438Sdteske			[ $# -gt 0 ] && echo -n ","
107238438Sdteske		done
108238438Sdteske		echo -n " ]"
109238438Sdteske	fi
110238438Sdteske
111238438Sdteske	echo ";"
112238438Sdteske}
113238438Sdteske
114238438Sdteske# print_node2 $node $node [$attributes ...]
115238438Sdteske#
116238438Sdteske# Print a directed node-node connection within a multi-node list.
117238438Sdteske#
118238438Sdteskeprint_node2()
119238438Sdteske{
120238438Sdteske	local node1="$1" node2="$2"
121238438Sdteske
122238438Sdteske	shift 2 # node1 node2
123238438Sdteske
124238438Sdteske	printf '\t\t"%s" -> "%s"' "$node1" "$node2"
125238438Sdteske
126238438Sdteske	if [ $# -gt 0 ]; then
127238438Sdteske		echo -n ' ['
128238438Sdteske		while [ $# -gt 0 ]; do
129238438Sdteske			printf " %s" "$1"
130238438Sdteske			shift 1
131238438Sdteske			[ $# -gt 0 ] && echo -n ","
132238438Sdteske		done
133238438Sdteske		echo -n " ]"
134238438Sdteske	fi
135238438Sdteske
136238438Sdteske	echo ";"
137238438Sdteske}
138238438Sdteske
139238438Sdteske# end_nodelist
140238438Sdteske#
141238438Sdteske# Close a multi-node list.
142238438Sdteske#
143238438Sdteskeend_nodelist()
144238438Sdteske{
145238438Sdteske	printf "\t};\n"
146238438Sdteske}
147238438Sdteske
148238438Sdteske############################################################ MAIN
149238438Sdteske
150238438Sdteske# Incorporate rc-file if it exists
151238438Sdteske[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
152238438Sdteske
153238438Sdteske#
154238438Sdteske# Process command-line arguments
155238438Sdteske#
156238438Sdteskewhile getopts cdhi flag; do
157238438Sdteske	case "$flag" in
158252178Sdteske	i) SHOW_INCLUDES= ;;
159252178Sdteske	d) SHOW_GRAPH_LABEL_DATE= ;;
160252178Sdteske	c) SHOW_CMDLINE= ;;
161252178Sdteske	h|\?) f_usage $BSDCFG_LIBE/$APP_DIR/USAGE "PROGRAM_NAME" "$pgm" ;;
162238438Sdteske	esac
163238438Sdteskedone
164238438Sdteskeshift $(( $OPTIND - 1 ))
165238438Sdteske
166260675Sdteskecd $BSDCFG_LIBE || f_die # Pedantic
167238438Sdteske
168238438Sdteske#
169238438Sdteske# Get a list of menu programs
170238438Sdteske#
171238438Sdteskemenu_program_list=
172238438Sdteskefor file in [0-9][0-9][0-9].*/INDEX; do
173238438Sdteske	menu_program_list="$menu_program_list $(
174238438Sdteske		tail -r "$file" | awk -v item="${file%%/*}" '
175238438Sdteske			/^[[:space:]]*menu_program="/ {
176238438Sdteske				sub(/^.*="/, "")
177238438Sdteske				sub(/"$/, "")
178238438Sdteske				if ( ! $0 ) next
179238438Sdteske				if ( $0 !~ "^/" ) sub(/^/, item "/")
180238438Sdteske				print; exit
181238438Sdteske			}'
182238438Sdteske	)"
183238438Sdteskedone
184238438Sdteske
185238438Sdteske#
186238438Sdteske# Get a list of submenu programs
187238438Sdteske#
188238438Sdteskesubmenu_program_list=
189238438Sdteskefor menu_program in $menu_program_list; do
190238438Sdteske	case "$menu_program" in
191238438Sdteske	[0-9][0-9][0-9].*/*) : fall-through ;;
192238438Sdteske	*) continue # No sub-menus we can process
193238438Sdteske	esac
194238438Sdteske
195238438Sdteske	submenu_program_list="$submenu_program_list $(
196238438Sdteske		awk -v menu_program="$menu_program" \
197238438Sdteske		    -v item="${menu_program%%/*}" \
198238438Sdteske		'
199238438Sdteske			/^menu_selection="/ {
200238438Sdteske				sub(/.*\|/, "")
201238438Sdteske				sub(/"$/, "")
202238438Sdteske				if ( ! $0 ) next
203238438Sdteske				if ( $0 !~ "^/" )
204238438Sdteske					sub(/^/, item "/")
205238438Sdteske				if ( $0 == menu_program ) next
206238438Sdteske				print
207238438Sdteske			}
208238438Sdteske		' "${menu_program%%/*}/INDEX"
209238438Sdteske	)"
210238438Sdteskedone
211238438Sdteske
212238438Sdteske#
213238438Sdteske# Get a list of command-line programs
214238438Sdteske#
215238438Sdteskecmd_program_list=
216238438Sdteskefor file in */INDEX; do
217238438Sdteske	cmd_program_list="$cmd_program_list $(
218238438Sdteske		awk -v item="${file%%/*}" '
219238438Sdteske			/^menu_selection="/ {
220238438Sdteske				sub(/.*\|/, "")
221238438Sdteske				sub(/"$/, "")
222238438Sdteske
223238438Sdteske				if ( ! $0 ) next
224238438Sdteske
225238438Sdteske				if ( $0 !~ "^/" )
226238438Sdteske					sub(/^/, item "/")
227238438Sdteske
228238438Sdteske				print
229238438Sdteske			}
230238438Sdteske		' $file
231238438Sdteske	)"
232238438Sdteskedone
233238438Sdteske
234238438Sdteske#
235238438Sdteske# [Optionally] Calculate list of include files
236238438Sdteske#
237238438Sdteskeif [ "$SHOW_INCLUDES" ]; then
238241499Sdteske	print_includes_awk='
239241499Sdteske		BEGIN { regex = "^f_include \\$BSDCFG_SHARE/" }
240241499Sdteske		( $0 ~ regex ) { sub(regex, ""); print }
241241499Sdteske	' # END-QUOTE
242241499Sdteske
243238438Sdteske	#
244238438Sdteske	# Build list of files in which to search for includes
245238438Sdteske	#
246238438Sdteske	file_list=$(
247238438Sdteske		for file in \
248238438Sdteske			$BSDCONFIG \
249238438Sdteske			$menu_program_list \
250238438Sdteske			$submenu_program_list \
251238438Sdteske			$cmd_program_list \
252272230Sdteske			$BSDCFG_SHARE/script.subr \
253238438Sdteske		; do
254238438Sdteske			[ -e "$file" ] && echo $file
255238438Sdteske		done | sort -u
256238438Sdteske	)
257238438Sdteske
258238438Sdteske	#
259238438Sdteske	# Build list of includes used by the above files
260238438Sdteske	#
261238438Sdteske	include_file_list=
262238438Sdteske	for file in $file_list; do
263238438Sdteske		include_file_list="$include_file_list $(
264250320Sdteske			awk "$print_includes_awk" $file
265238438Sdteske		)"
266238438Sdteske	done
267238438Sdteske
268238438Sdteske	#
269238438Sdteske	# Sort the list of includes and remove duplicate entries
270238438Sdteske	#
271238438Sdteske	include_file_list=$(
272238438Sdteske		for include_file in $include_file_list; do
273238438Sdteske			echo "$include_file"
274238438Sdteske		done | sort -u
275238438Sdteske	)
276238438Sdteske
277238438Sdteske	#
278238438Sdteske	# Search previously-discovered include files for further includes
279238438Sdteske	#
280250321Sdteske	before="$include_file_list"
281250321Sdteske	while :; do
282250321Sdteske		for file in $include_file_list; do
283250321Sdteske			include_file_list="$include_file_list $(
284250321Sdteske				awk "$print_includes_awk" $BSDCFG_SHARE/$file
285250321Sdteske			)"
286250321Sdteske		done
287250321Sdteske
288250321Sdteske		#
289250321Sdteske		# Sort list of includes and remove duplicate entries [again]
290250321Sdteske		#
291250321Sdteske		include_file_list=$(
292250321Sdteske			for include_file in $include_file_list; do
293250321Sdteske				echo "$include_file"
294250321Sdteske			done | sort -u
295250321Sdteske		)
296250321Sdteske
297250321Sdteske		[ "$include_file_list" = "$before" ] && break
298250321Sdteske		before="$include_file_list"
299238438Sdteske	done
300238438Sdteskefi
301238438Sdteske
302238438Sdteske#
303238438Sdteske# Start the directional-graph (digraph) output
304238438Sdteske#
305238438Sdteskeprintf 'strict digraph "" { // Empty name to prevent SVG Auto-Tooltip\n'
306238438Sdteskelabel_format="$msg_graph_label_with_command"
307238438Sdteske[ "$SHOW_GRAPH_LABEL_DATE" ] &&
308238438Sdteske	label_format="$msg_graph_label_with_command_and_date"
309238438Sdteskelang="${LANG:-$LC_ALL}"
310238438Sdteskeprintf "\n\tlabel = \"$label_format\"\n" \
311238438Sdteske       "${lang:+LANG=${lang%%[$IFS]*} }bsdconfig $pgm${ARGV:+ $ARGV}" \
312238438Sdteske       "$( date +"%c %Z" )"
313238438Sdteske
314238438Sdteske#
315238438Sdteske# Print graph-specific properties
316238438Sdteske#
317238438Sdteskeprintf '\n\t/*\n\t * Graph setup and orientation\n\t */\n'
318238438Sdteskeprintf '\tlabelloc = top;\t\t// display above label at top of graph\n'
319238438Sdteskeprintf '\trankdir = LR;\t\t// create ranks left-to-right\n'
320238438Sdteskeprintf '\torientation = portrait;\t// default\n'
321238438Sdteskeprintf '\tratio = fill;\t\t// approximate aspect ratio\n'
322238438Sdteskeprintf '\tcenter = 1;\t\t// center drawing on page\n'
323238438Sdteske
324238438Sdteske#
325238438Sdteske# Perform edge-concentration when displaying a lot of information
326238438Sdteske#
327251910Sdteske# NOTE: This is disabled because dot(1) version 2.28.0 (current) and older have
328251910Sdteske#       a bug that causes a crash when rankdir = LR and concentrate = true
329238438Sdteske#
330238438Sdteske# NOTE: Do not re-enable until said bug is fixed in some future revision.
331238438Sdteske#
332238438Sdteske#[ "$SHOW_INCLUDES" -a "$SHOW_CMDLINE" ] &&
333238438Sdteske#	printf '\tconcentrate = true;\t// enable edge concentrators\n'
334238438Sdteske
335238438Sdteske#
336238438Sdteske# Print font details for graph/cluster label(s)
337238438Sdteske#
338238438Sdteskeprintf '\n\t/*\n\t * Font details for graph/cluster label(s)\n\t */\n'
339238438Sdteskeprintf '\tfontname = "Times-Italic";\n'
340238438Sdteskeprintf '\tfontsize = 14;\n'
341238438Sdteske
342238438Sdteske#
343238438Sdteske# Print default node attributes
344238438Sdteske#
345238438Sdteskeprintf '\n\t/*\n\t * Default node attributes\n\t */\n'
346238438Sdteskeprintf '\tnode [\n'
347238438Sdteskeprintf '\t\tfontname = "Times-Roman",\n'
348238438Sdteskeprintf '\t\tfontsize = 12,\n'
349238438Sdteskeprintf '\t\twidth = 2.5, // arbitrary minimum width for all nodes\n'
350272230Sdteskeprintf '\t\tfixedsize = true, // turn minimum width into exact width\n'
351238438Sdteskeprintf '\t];\n'
352238438Sdteske
353238438Sdteske#
354238438Sdteske# Print top-level item(s)
355238438Sdteske#
356238438Sdteskeprintf '\n\t/*\n\t * bsdconfig(8)\n\t */\n'
357238438Sdteskeshape=circle color=black fillcolor=yellow style=filled
358238438Sdteskebegin_nodelist "$shape" "$color" "$fillcolor" "$style"
359238438Sdteskeprint_node "bsdconfig" "fontname = \"Times-Bold\"" "fontsize = 16"
360238438Sdteskeend_nodelist
361238438Sdteske
362238438Sdteske#
363238438Sdteske# Print menus
364238438Sdteske#
365238438Sdteskeprintf '\n\t/*\n\t * Menu items\n\t */\n'
366238438Sdteskeshape=box color=black fillcolor=lightblue style=filled
367238438Sdteskebegin_nodelist "$shape" "$color" "$fillcolor" "$style"
368238438Sdteskefor menu_program in $menu_program_list; do
369238438Sdteske	print_node "$menu_program" "label = \"${menu_program#*/}\""
370238438Sdteskedone
371238438Sdteskeend_nodelist
372238438Sdteske
373238438Sdteske#
374238438Sdteske# Print sub-menus
375238438Sdteske#
376238438Sdteskeprintf '\n\t/*\n\t * Sub-menu items\n\t */\n'
377238438Sdteskeshape=box color=black fillcolor=lightblue style=filled
378238438Sdteskebegin_nodelist "$shape" "$color" "$fillcolor" "$style"
379238438Sdteskefor submenu_program in $submenu_program_list; do
380238438Sdteske	print_node "$submenu_program" "label = \"${submenu_program#*/}\""
381238438Sdteskedone
382238438Sdteskeend_nodelist
383238438Sdteske
384238438Sdteske#
385238438Sdteske# Print menu relationships
386238438Sdteske#
387238438Sdteskeprintf '\n\t/*\n\t * Menu item relationships\n\t */\n'
388238438Sdteskeshape=box color=black fillcolor=lightblue style=filled edge_color=blue
389238438Sdteskebegin_nodelist "$shape" "$color" "$fillcolor" "$style"
390238438Sdteskeprint_node edge "penwidth = 5.0" "style = bold" "color = $edge_color"
391238438Sdteskefor menu_program in $menu_program_list; do
392238438Sdteske	print_node2 "bsdconfig" "$menu_program"
393238438Sdteskedone
394238438Sdteskeend_nodelist
395238438Sdteske
396238438Sdteske#
397238438Sdteske# Print sub-menu relationships
398238438Sdteske#
399238438Sdteskeprintf '\n\t/*\n\t * Sub-menu item relationships\n\t */\n'
400238438Sdteskeshape=box color=black fillcolor=lightblue style=filled edge_color=blue
401238438Sdteskebegin_nodelist "$shape" "$color" "$fillcolor" "$style"
402238438Sdteske# Lock sub-menu headport to the West (unless `-c' was passed)
403238438Sdteske[ "$SHOW_CMDLINE" -o ! "$SHOW_INCLUDES" ] && print_node edge "headport = w"
404238438Sdteskeprint_node edge "style = bold" "color = $edge_color"
405238438Sdteskefor submenu_program in $submenu_program_list; do
406238438Sdteske	for menu_program in $menu_program_list; do
407238438Sdteske		case "$menu_program" in
408238438Sdteske		[0-9][0-9][0-9].*/*) : fall-through ;;
409238438Sdteske		*) continue # Not a menu item
410238438Sdteske		esac
411238438Sdteske
412238438Sdteske		# Continue if program directories do not match
413238438Sdteske		[ "${menu_program%%/*}" = "${submenu_program%%/*}" ] ||
414238438Sdteske			continue
415238438Sdteske
416238438Sdteske		print_node2 "$menu_program" "$submenu_program"
417238438Sdteske		break
418238438Sdteske	done
419238438Sdteskedone
420238438Sdteskeend_nodelist
421238438Sdteske
422238438Sdteske#
423238438Sdteske# [Optionally] Print include files
424238438Sdteske#
425238438Sdteskeif [ "$SHOW_INCLUDES" ]; then
426238438Sdteske	printf '\n\t/*\n\t * Include files\n\t */\n'
427238438Sdteske	shape=oval color=black fillcolor=white style=filled
428238438Sdteske	begin_nodelist "$shape" "$color" "$fillcolor" "$style"
429238438Sdteske	printf '\t\tconstraint = false;\n'
430238438Sdteske	for include_file in $include_file_list; do
431238438Sdteske		print_node "$include_file" \
432241499Sdteske		           "label = \"${include_file##*/}\""
433238438Sdteske	done
434238438Sdteske	end_nodelist
435238438Sdteskefi
436238438Sdteske
437238438Sdteske#
438238438Sdteske# [Optionally] Print f_include() usage/relationships
439238438Sdteske#
440238438Sdteskeif [ "$SHOW_INCLUDES" ]; then
441238438Sdteske	printf '\n\t/*\n\t * Include usage\n\t */\n'
442238438Sdteske	shape=oval color=black fillcolor=white style=filled edge_color=grey
443238438Sdteske	begin_nodelist "$shape" "$color" "$fillcolor" "$style"
444238438Sdteske	print_node edge "style = dashed" "color = $edge_color"
445250321Sdteske	#print_node edge "label = \"\\T\"" "fontsize = 9"
446250321Sdteske		# NOTE: Edge labels are buggy on large graphs
447238438Sdteske	file_list=$(
448238438Sdteske		for file in \
449238438Sdteske			$BSDCONFIG \
450238438Sdteske			$menu_program_list \
451238438Sdteske			$submenu_program_list \
452238438Sdteske			$cmd_program_list \
453238438Sdteske			$include_file_list \
454238438Sdteske		; do
455241499Sdteske			[ -f "$BSDCFG_SHARE/$file" ] &&
456241499Sdteske				echo $BSDCFG_SHARE/$file
457238438Sdteske			[ -e "$file" ] && echo $file
458238438Sdteske		done | sort -u
459238438Sdteske	)
460238438Sdteske	for file in $file_list; do
461238438Sdteske		# Skip binary files and text files that don't use f_include()
462238438Sdteske		grep -qlI f_include $file || continue
463238438Sdteske
464238438Sdteske		awk \
465241499Sdteske			-v file="${file#$BSDCFG_SHARE/}" \
466238438Sdteske			-v bsdconfig="$BSDCONFIG" \
467238438Sdteske		'
468241499Sdteske			BEGIN { regex = "^f_include \\$BSDCFG_SHARE/" }
469241499Sdteske			( $0 ~ regex ) {
470238438Sdteske				sub(regex, "")
471238438Sdteske				if ( file == bsdconfig ) sub(".*/", "", file)
472238438Sdteske				printf "\t\t\"%s\" -> \"%s\";\n", $0, file
473238438Sdteske			}
474238438Sdteske		' $file
475241499Sdteske	done | sort
476238438Sdteske	end_nodelist
477238438Sdteskefi
478238438Sdteske
479238438Sdteske#
480238438Sdteske# Print command-line shortcuts
481238438Sdteske#
482238438Sdteskeif [ "$SHOW_CMDLINE" ]; then
483238438Sdteske	printf '\n\t/*\n\t * Command-line shortcuts\n\t */\n'
484238438Sdteske	shape=parallelogram color=black fillcolor=lightseagreen style=filled
485238438Sdteske	begin_nodelist "$shape" "$color" "$fillcolor" "$style"
486238438Sdteske	for file in */INDEX; do
487238438Sdteske		awk -v item="${file%%/*}" '
488238438Sdteske			/^menu_selection="/ {
489238438Sdteske				sub(/^.*="/, "")
490238438Sdteske				sub(/\|.*/, "")
491238438Sdteske				printf "\t\t\"bsdconfig %s\"", $0
492238438Sdteske				printf " [ label = \"%s\" ];\n", $0
493238438Sdteske			}
494238438Sdteske		' $file
495238438Sdteske	done
496238438Sdteske	end_nodelist
497238438Sdteskefi
498238438Sdteske
499238438Sdteske#
500238438Sdteske# Print command-line shortcut relationships
501238438Sdteske#
502238438Sdteskeif [ "$SHOW_CMDLINE" ]; then
503238438Sdteske	printf '\n\t/*\n\t * Command-line shortcut relationships\n\t */\n'
504238438Sdteske	shape=box color=black fillcolor=lightseagreen style=filled
505238438Sdteske	begin_nodelist "$shape" "$color" "$fillcolor" "$style"
506238438Sdteske	print_node edge "headport = w" "weight = 100.0"
507238438Sdteske	print_node edge "style = bold" "color = $fillcolor"
508238438Sdteske	for file in */INDEX; do
509238438Sdteske		awk -v item="${file%%/*}" \
510238438Sdteske		    -v node_fillcolor="$node_fillcolor" \
511238438Sdteske		    -v edge_color="$edge_color" \
512238438Sdteske		'
513238438Sdteske			/^menu_selection="/ {
514238438Sdteske				sub(/^.*="/, "")
515238438Sdteske				sub(/"$/, "")
516238438Sdteske
517238438Sdteske				if ( ! $0 ) next
518238438Sdteske
519238438Sdteske				split($0, menusel, "|")
520238438Sdteske				if ( menusel[2] !~ "^/" )
521238438Sdteske					sub(/^/, item "/", menusel[2])
522238438Sdteske
523238438Sdteske				printf "\t\t\"bsdconfig %s\" -> \"%s\";\n",
524238438Sdteske				       menusel[1], menusel[2]
525238438Sdteske			}
526238438Sdteske		' $file
527238438Sdteske	done
528238438Sdteske	end_nodelist
529238438Sdteskefi
530238438Sdteske
531238438Sdteske#
532238438Sdteske# Print clusters
533238438Sdteske#
534238438Sdteskebgcolor_bsdconfig="lightyellow"
535238438Sdteskebgcolor_includes="gray98"
536238438Sdteskebgcolor_menuitem="aliceblue"
537238438Sdteskebgcolor_shortcuts="honeydew"
538238438Sdteskeprintf '\n\t/*\n\t * Clusters\n\t */\n'
539238438Sdteskeprintf '\tsubgraph "cluster_bsdconfig" {\n'
540238438Sdteskeprintf '\t\tbgcolor = "%s";\n' "$bgcolor_bsdconfig"
541238438Sdteskeprintf '\t\tlabel = "bsdconfig(8)";\n'
542238438Sdteskeprintf '\t\ttooltip = "bsdconfig(8)";\n'
543238438Sdteskeprint_node "bsdconfig"
544272230Sdteskeend_nodelist
545238438Sdteskeif [ "$SHOW_INCLUDES" ]; then
546238438Sdteske	for include_file in $include_file_list; do
547241499Sdteske		echo $include_file
548272230Sdteske	done | awk \
549272230Sdteske		-v bgcolor="$bgcolor_bsdconfig" \
550272230Sdteske		-v msg_subroutines="$msg_subroutines" \
551272230Sdteske	'
552272230Sdteske		BEGIN { created = 0 }
553272230Sdteske		function end_subgraph() { printf "\t};\n" }
554272230Sdteske		( $0 !~ "/" ) {
555272230Sdteske			if ( ! created )
556272230Sdteske			{
557272230Sdteske				printf "\tsubgraph \"%s\" {\n",
558272230Sdteske				       "cluster_bsdconfig_includes"
559272230Sdteske				printf "\t\tbgcolor = \"%s\";\n", bgcolor
560272230Sdteske				printf "\t\tlabel = \"bsdconfig %s\";\n",
561272230Sdteske				       msg_subroutines
562272230Sdteske				created++
563272230Sdteske			}
564272230Sdteske			printf "\t\t\"%s\";\n", $1
565241499Sdteske		}
566272230Sdteske		END { created && end_subgraph() }
567272230Sdteske	' # END-QUOTE
568241499Sdteske
569241499Sdteske	for include_file in $include_file_list; do
570241499Sdteske		echo $include_file
571272230Sdteske	done | awk -v msg_subroutines="$msg_subroutines" '
572241499Sdteske	BEGIN { created = 0 }
573272230Sdteske	function end_subgraph() { printf "\t};\n" }
574241499Sdteske	( $0 ~ "/" ) {
575241499Sdteske		include_dir_tmp = $1
576241499Sdteske		sub("/[^/]*$", "", include_dir_tmp)
577241499Sdteske		gsub(/[^[:alnum:]_]/, "_", include_dir_tmp)
578241499Sdteske
579241499Sdteske		if ( created && include_dir != include_dir_tmp )
580241499Sdteske		{
581241499Sdteske			end_subgraph()
582241499Sdteske			created = 0
583241499Sdteske		}
584241499Sdteske
585241499Sdteske		if ( ! created )
586241499Sdteske		{
587241499Sdteske			include_dir = include_dir_tmp
588272230Sdteske			printf "\tsubgraph \"cluster_%s_includes\" {\n",
589241499Sdteske			       include_dir
590272230Sdteske			printf "\t\tbgcolor = \"thistle\";\n"
591272230Sdteske			printf "\t\tlabel = \"%s %s\";\n", include_dir,
592272230Sdteske			       msg_subroutines
593241499Sdteske			created++
594241499Sdteske		}
595241499Sdteske
596272230Sdteske		printf "\t\t\"%s\";\n", $1
597241499Sdteske	}
598241499Sdteske	END { created && end_subgraph() }'
599238438Sdteskefi
600238438Sdteskefor INDEX in */INDEX; do
601238438Sdteske	menu_title=
602238438Sdteske	menu_help=
603238438Sdteske	f_include_lang "$INDEX"
604238438Sdteske
605238438Sdteske	item="${INDEX%%/*}"
606238438Sdteske	printf '\tsubgraph "cluster_%s" {\n' "$item"
607238438Sdteske
608238438Sdteske	case "$item" in
609252178Sdteske	[0-9][0-9][0-9].*) bgcolor="$bgcolor_menuitem" ;;
610238438Sdteske	*) bgcolor="$bgcolor_shortcuts"
611238438Sdteske	esac
612238438Sdteske	printf '\t\tbgcolor = "%s";\n' "$bgcolor"
613238438Sdteske	if [ "$menu_title" ]; then
614238438Sdteske		printf '\t\tlabel = "%s\\n\\"%s\\"";\n' "$item" "$menu_title"
615238438Sdteske	else
616238438Sdteske		printf '\t\tlabel = "%s";\n' "$item"
617238438Sdteske	fi
618238438Sdteske	printf '\t\ttooltip = "%s";\n' "${menu_help:-$item}"
619238438Sdteske
620238438Sdteske	program_list=$(
621238438Sdteske		for program in \
622238438Sdteske			$menu_program_list \
623238438Sdteske			$submenu_program_list \
624238438Sdteske			$cmd_program_list \
625238438Sdteske		; do
626238438Sdteske			echo "$program"
627238438Sdteske		done | sort -u
628238438Sdteske	)
629238438Sdteske	for program in $program_list; do
630238438Sdteske		case "$program" in "$item"/*)
631238438Sdteske			print_node "$program" "label = \"${program#*/}\""
632238438Sdteske		esac
633238438Sdteske	done
634238438Sdteske
635238438Sdteske	if [ "$SHOW_INCLUDES" ]; then
636238438Sdteske		item_include_list=
637238438Sdteske		[ -d "$item/include" ] &&
638238438Sdteske			item_include_list=$( find "$item/include" -type f )
639238438Sdteske		item_include_list=$(
640238438Sdteske			for item_include in $item_include_list; do
641238438Sdteske				for include_file in $include_file_list; do
642238438Sdteske					[ "$item_include" = "$include_file" ] ||
643238438Sdteske						continue
644238438Sdteske					echo "$item_include"; break
645238438Sdteske				done
646238438Sdteske			done
647238438Sdteske		)
648238438Sdteske		if [ "$item_include_list" ]; then
649238438Sdteske			printf '\t\tsubgraph "cluster_%s_includes" {\n' "$item"
650238438Sdteske			printf '\t\t\tbgcolor = "%s";\n' "$bgcolor_includes"
651238438Sdteske			printf '\t\t\tlabel = "%s";\n' "$msg_includes"
652238438Sdteske		fi
653238438Sdteske		for item_include in $item_include_list; do
654238438Sdteske			printf '\t\t\t"%s";\n' "$item_include"
655238438Sdteske		done
656238438Sdteske		[ "$item_include_list" ] && printf '\t\t};\n'
657238438Sdteske	fi
658238438Sdteske
659238438Sdteske	if [ "$SHOW_CMDLINE" ]; then
660238438Sdteske		printf '\t\tsubgraph "cluster_%s_shortcuts" {\n' "$item"
661238438Sdteske		printf '\t\t\tbgcolor = "%s";\n' "$bgcolor_shortcuts"
662238438Sdteske		printf '\t\t\tlabel = "%s";\n' "$msg_shortcuts"
663238438Sdteske		awk '/^menu_selection="/ {
664238438Sdteske			sub(/^.*="/, "")
665238438Sdteske			sub(/\|.*/, "")
666238438Sdteske			printf "\t\t\t\"bsdconfig %s\";\n", $0
667238438Sdteske		}' "$INDEX"
668238438Sdteske		printf '\t\t};\n'
669238438Sdteske	fi
670238438Sdteske
671238438Sdteske	end_nodelist
672238438Sdteskedone
673238438Sdteske
674272230Sdteskeprintf '\n}\n'
675238438Sdteske
676238438Sdteske################################################################################
677238438Sdteske# END
678238438Sdteske################################################################################
679