summaryrefslogtreecommitdiff
path: root/mk/help/help.awk
blob: 465cc3bd8666d013622f5bc7707108966a9404df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# $NetBSD: help.awk,v 1.16 2007/08/14 18:04:16 rillig Exp $
#

# This program extracts the inline documentation from *.mk files.
#
# usage: env TOPIC="topic" awk help.awk file...
#

BEGIN {
	no = 0; yes = 1; always = 1;

	topic = ENVIRON["TOPIC"];
	uctopic = toupper(topic);
	lctopic = tolower(topic);

	found_anything = no;	# has some help text been found at all?
	last_fname = "";
	this_line_maybe_definition = yes;
	ignore_this_line = no;
	ignore_next_empty_line = no;

	delete lines;		# the collected lines
	relevant = no;		# are the current lines relevant?
	nlines = 0;		# the number of lines collected so far
	comment_lines = 0;	# the number of comment lines so far
	print_noncomment_lines = yes; # for make targets, this isn't useful
}

# Help topics are separated by either completely empty lines or by the
# end of a file or by the end of all files. When here have been enough
# comment lines, the topic is considered worth printing.
#
function end_of_topic() {
	if (relevant && comment_lines > 2) {
		if (found_anything)
			print "";
		found_anything = yes;
		print "===> "last_fname":";
		for (i = 0; i < nlines; i++) {
			if (print_noncomment_lines || (lines[i] ~ /^#/))
				print lines[i];
		}
	}

	ignore_next_empty_line = yes;
	delete lines;
	relevant = no;
	nlines = 0;
	comment_lines = 0;
	print_noncomment_lines = yes;
}

always {
	ignore_this_line = (ignore_next_empty_line && $0 == "#") || $0 == "";
	ignore_next_empty_line = no;
	this_line_is_definition = no;
}

# There is no need to print the RCS Id, since the full pathname
# is prefixed to the file contents.
/^#.*\$.*\$$/ {
	ignore_this_line = yes;
	ignore_next_empty_line = yes;
}

# The lines containing the keywords should also not appear in
# the output for now. This decision is not final since it may
# be helpful for the user to know by which keywords a topic
# can be reached.
($1 == "#" && $2 == "Keywords:") {
	for (i = 3; i <= NF; i++) {
		w = ($i == toupper($i)) ? tolower($i) : $i;
		if (w == lctopic || w == lctopic",") {
			relevant = yes;
		}
	}
	ignore_this_line = yes;
	ignore_next_empty_line = yes;
}

($0 == "#") {
	ignore_next_empty_line = no;
}

# Don't show the user the definition of make targets, since they are
# usually not interesting enough. This allows the comments to reach
# until the line directly above the target definition.
#
$1 ~ /:$/ && $2 == ".PHONY" {
	end_of_topic();
}

(!ignore_this_line) {
	lines[nlines++] = $0;
}

# Check whether the current line contains a keyword. Such a keyword must
# be all-lowercase (make targets) or all-uppercase (variable names).
# Everything else is assumed to belong to the explaining text.
#
NF >= 1 {
	# Reduce FOO.<param> and FOO.${param} to FOO.
	w1 = gensub(/\.[<$].*[>}]$/, "", "g", $1);
	w2 = gensub(/\.[<$].*[>}]$/, "", "g", $2);

	# Convert all-lowercase words to all-uppercase.
	w1 = (w1 == tolower(w1)) ? toupper(w1) : w1;
	w2 = (w2 == tolower(w2)) ? toupper(w2) : w2;

	this_line_is_definition = (w1 == toupper($1)) && (w2 == toupper($2));

	if ((w1 == uctopic"?=") ||
	    (w1 == uctopic"=") ||
	    (index(w1, "#"uctopic"=") == 1) ||
	    (index(w1, "#"uctopic"?=") == 1) ||
	    (this_line_maybe_definition &&
	        w1 == "#" &&
	        (w2 == uctopic || w2 == uctopic":"))) {
		relevant = yes;
	}
}

# Don't print the implementation of make targets.
$1 == uctopic":" {
	print_noncomment_lines = no;
}

$1 == "#" {
	comment_lines++;
}

/^$/ || last_fname != FILENAME {
	end_of_topic();
}

always {
	# Note: The first "this" actually means the next line.
	this_line_maybe_definition = (/^#$/ || /^$/) || this_line_is_definition;
	last_fname = FILENAME;
}

END {
	end_of_topic();
	if (!found_anything) {
		print "No help found for "topic".";
	}
}