#!/usr/local/bin/perl
#
#	generate public and private header files

$incl='incl';
$pubsuf='.pub.h';
$pvtsuf='.pvt.h';

opendir(DOT, ".") || die ".: $!\n";
@names = sort grep(($_)=/(.+)\.c$/, readdir(DOT));
closedir(DOT);

@names || die ".: no c files\n";

unless (-d $incl) {
	mkdir($incl, 644) || die "$incl: $!\n";
}

#
#	update public header files
#
for (@names) {
	if (! -e "$incl/$_$pubsuf" || -M _ > -M "$_.c") {
		print "writing $incl/$_$pubsuf\n";
		system "./mkproto -e $_.c > $incl/$_$pubsuf";
	}
}

#
#	read in all public entries
#
for $name (@names) {
	open(FD, "$incl/$name$pubsuf") || die "$incl/$name$pubsuf: $!\n";
	for (<FD>) {
		/^extern FUNC\([^,]+, (\w+),/ && do {
			$rtns{$1} = $name;
		};
	}
}
close(FD);

#
#	build matching routine as a string and eval it
#
$match = 'sub match {
	$_ = shift @_;
';
while (($rtn, $name) = each rtns) {
	$match .= "/\\b$rtn\\b/ && do {\$files{'$name'} = 1;};\n";
}
$match .= "\n}\n1;";

eval $match || die "eval \$match: $@\n";

#
#	update private header files
#
for (@names) {
	if (! -e "$incl/$_$pvtsuf" || -M _ > -M "$_.c") {
		print "writing $incl/$_$pvtsuf\n";
		&mkprivate($_);
	}
}
exit(0);


sub mkprivate {
	local($name) = @_;
	local(%files, $incom);

	%files = ();
	open(FD, "$name.c") || die "$name.c: $!\n";
	for (<FD>) {
		$incom && do {
			m#^([^*]|(\*+[^/*]))*\*+/# || next;
			$_ = $';
			$incom = 0;
		};
		s#/\*([^*]|(\*+[^/*]))*\*+/##g;
		m#/\*([^*]|(\*+[^/*]))*$# && do {
			$incom = 1;
			$_ = $`;
		};
		s/"([^"]|(\\"))*"//g;			# strip strings
		&match($_);
	}
	@files = keys %files;

	open(MKPROTO, "./mkproto -s $name.c |") || die "mkproto: $!\n";

	open(FD, ">$incl/$name$pvtsuf") || die "$incl/$name$pvtsuf: $!\n";
	truncate(FD, 0);
	for (sort @files) {
		print FD "#include \"$_$pubsuf\"\n";
	}
	for (<MKPROTO>) {
		print FD $_;
	}
	close(MKPROTO);
}
