#!/usr/local/bin/perl
#
#   mkproto
#
#	Create function prototypes from c code.  This is not a general
#	purpose utility - it relies on coding conventions used here.
#	Doesn't do function pointer types.
#
#	This is a big fat hack.

$usage='usage: mkproto [-es] [file]';

require 'getopts.pl';
&Getopts('es') || die $usage;

for (<>) {
	s#/\*([^*]|(\*[^/]))*\*/##g;
	length $line && do {
		$cont && do {
			next if /,\s*$/;
			$cont = 0;
			next;
		};
		/^\s+D([DB])\s+(.*)$/ && do {
			$comma = $1 eq 'D' ? ', ' : '';
			if ($type = &typeof($2)) {
				$len += length($comma) + length($type);
				if ($len > 75) {
					$line .= "$comma\n\t$type";
					$len = 8 + length($type);
				}
				else {
					$line .= $comma . $type;
				}
				next;
			};
		};
		/^\s+DE/ && do {
			$line .= '));';
			if ($static) {
				push(@static, $line);
			}
			else {
				push(@extern, $line);
			}
			$line = '';
			next;
		};
		die "line $.: bad syntax\n";
	};
	/^\s+(AL|VOID|VARARG)\b/ && do {
		$argtype = $1;
		$tail = $';

		($routine) = $routine =~ /^([\w_]+)/;
		($static, $ftype) =
			$ftype =~ /^(static\s+)?([\w_* ]+[\w*])\s*$/;
		$line = "FUNC( $ftype, $routine, (";

		if ($argtype eq 'AL') {
			$cont = 1 if $tail =~ /,\s*$/;
			$len = 7 + length($line);
		}
		else {
			if ($argtype eq 'VOID') {
				$line .= 'void));';
			}
			elsif ($argtype eq 'VARARG') {
				if ($tail =~ /\(\((.*)\)\)/) {
					@proto = split(/,/, $1);
					for (@proto) {
						$_ = &typeof($_)
							unless /^\s*\.\.\.$/;
					}
					$line .= join(',', @proto) . '));';
				}
			}
			if ($static) {
				push(@static, $line);
			}
			else {
				push(@extern, $line);
			}
			$line = '';
		}
		next;
	};
	$ftype = $routine;
	$routine = $_;
}

if ($opt_e && @extern != 0) {
	print "extern ", join("\nextern ", @extern), "\n";
}

if ($opt_s && @static != 0) {
	print "static ", join("\nstatic ", @static), "\n";
}

sub typeof {
	local($type);
	$_ = $_[0];

	if (/^([\w_ ]*[\w_])\s+[\w_]+\s*$/ || /^([\w_ ]+\*+)\s*[\w_]+\s*$/) {
		$type = $1;
	}
	else {
		$type = '';
	}
	$type;
}
