1#!/usr/bin/awk -f
2#
3# Combine multiple pkg-plist files into a single pkg-plist.
4#
5# This takes a list of all options as command line arguments. The
6# order of the options determines the order option specific plist
7# entries appear in the combined output.
8#
9# The plists must be fed into stdin and preceded by a line starting
10# with `OPTIONS:` followed by a white space separated list of the
11# active options.
12#
13# Files that appear with all options are listed first, followed by
14# the option specific output.
15#
16# @param ARGV
17#	A sorted list of options
18#
19
20# Get the order of options
21BEGIN {
22	OPTION_STR["DOCS"] =     "%%PORTDOCS%%"
23	OPTION_STR["EXAMPLES"] = "%%PORTEXAMPLES%%"
24	for (i = 1; i < ARGC; ++i) {
25		OPTIONS_ORDERD[i] = ARGV[i]
26		CNT_OPT_FILES[ARGV[i]] = 0
27		if (!(ARGV[i] in OPTION_STR)) {
28			OPTION_STR[ARGV[i]] = "%%" ARGV[i] "%%"
29		}
30		if (!("NO_" ARGV[i] in OPTION_STR)) {
31			OPTION_STR["NO_" ARGV[i]] = "%%NO_" ARGV[i] "%%"
32		}
33		delete ARGV[i]
34	}
35	CNT_FILES = 0
36}
37
38# Get the options the following files were staged with
39/^OPTIONS:/ {
40	delete aoptions
41	sub(/^OPTIONS: */, "")
42	cnt_aoptions = split($0, aoptions)
43	for (i = 1; i <= cnt_aoptions; ++i) {
44		++OPTIONS[aoptions[i]]
45	}
46	++CONFIGS
47	next
48}
49
50# Collect files
51{
52	# Record order of file
53	if (!($0 in FILES)) {
54		FILES_ORDERED[++CNT_FILES] = $0
55	}
56	# Count occurence of file
57	++FILES[$0]
58	# The same book keepin per option
59	for (i = 1; i <= cnt_aoptions; ++i) {
60		option = aoptions[i]
61		# Record order of file for option
62		if (!OPT_FILES[option, $0]) {
63			OPT_FILES_ORDERED[option, ++CNT_OPT_FILES[option]] = $0
64		}
65		# Count occurence of file by option
66		++OPT_FILES[option, $0]
67	}
68}
69
70# Print files
71END {
72	# Print files common to all configurations
73	for (i = 1; i <= CNT_FILES; ++i) {
74		file = FILES_ORDERED[i]
75		if (FILES[file] == CONFIGS) {
76			print file
77			delete FILES[file]
78		}
79	}
80	# Print option specific files
81	for (i = 1; OPTIONS_ORDERD[i]; ++i) {
82		option = OPTIONS_ORDERD[i]
83		for (p = 1; p <= CNT_OPT_FILES[option]; ++p) {
84			file = OPT_FILES_ORDERED[option, p]
85			# Skip files that have already been printed
86			if (!(file in FILES)) { continue }
87			# Print file if it only occurs for the current
88			# option
89			if (OPT_FILES[option, file] == OPTIONS[option] &&
90			    OPT_FILES[option, file] == FILES[file]) {
91				print OPTION_STR[option] file
92				delete FILES[file]
93			}
94		}
95		for (p = 1; p <= CNT_FILES; ++p) {
96			file = FILES_ORDERED[p]
97			if (!(file in FILES)) { continue }
98			# Print file if it occurs everywhere but with
99			# this option
100			if (!OPT_FILES[option, file] &&
101			    FILES[file] + OPTIONS[option] == CONFIGS) {
102				print OPTION_STR["NO_" option] file
103				delete FILES[file]
104			}
105		}
106	}
107	# Print all files that have not been printed
108	for (i = 1; i <= CNT_FILES; ++i) {
109		file = FILES_ORDERED[i]
110		if (!(file in FILES)) { continue }
111		print "@fail " file " could not be mapped to an option!"
112		msg = "@fail Candidates:"
113		for (p = 1; OPTIONS_ORDERD[p]; ++p) {
114			if (OPT_FILES[OPTIONS_ORDERD[p], file]) {
115				msg = msg " " OPTIONS_ORDERD[p]
116			}
117		}
118		print msg
119	}
120}
121