- Begun implementation of a C statements parser.
- More reorganizations and fixes.

diff --git a/tools/winapi/c_parser.pm b/tools/winapi/c_parser.pm
new file mode 100644
index 0000000..957723a
--- /dev/null
+++ b/tools/winapi/c_parser.pm
@@ -0,0 +1,534 @@
+package c_parser;
+
+use strict;
+
+use options qw($options);
+use output qw($output);
+
+sub _update_c_position {
+    local $_ = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    while($_) {
+	if(s/^[^\n\t\'\"]*//s) {
+	    $column += length($&);
+	}
+
+	if(s/^\'//) {
+	    $column++;
+	    while(/^./ && !s/^\'//) {
+		s/^([^\'\\]*)//s;
+		$column += length($1);
+		if(s/^\\//) {
+		    $column++;
+		    if(s/^(.)//s) {
+			$column += length($1);
+			if($1 eq "0") {
+			    s/^(\d{0,3})//s;
+			    $column += length($1);
+			}
+		    }
+		}
+	    }
+	    $column++;
+	} elsif(s/^\"//) {
+	    $column++;
+	    while(/^./ && !s/^\"//) {
+		s/^([^\"\\]*)//s;
+		$column += length($1);
+		if(s/^\\//) {
+		    $column++;
+		    if(s/^(.)//s) {
+			$column += length($1);
+			if($1 eq "0") {
+			    s/^(\d{0,3})//s;
+			    $column += length($1);
+			}
+		    }
+		}
+	    }
+	    $column++;
+	} elsif(s/^\n//) {
+	    $line++;
+	    $column = 0;
+	} elsif(s/^\t//) {
+	    $column = $column + 8 - $column % 8;
+	}
+    }
+
+    $$refline = $line;
+    $$refcolumn = $column;
+}
+
+sub parse_c {
+    my $pattern = shift;
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    if(s/$pattern//) {
+	_update_c_position($&, \$line, \$column);
+    } else {
+	return 0;
+    }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    return 1;
+}
+
+sub parse_c_until_one_of {
+    my $characters = shift;
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+    my $match = shift;
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    if(!defined($line) || !defined($column)) {
+	$output->write("error: \$characters = '$characters' \$_ = '$_'\n");
+	exit 1;
+    }
+
+    if(!defined($match)) {
+	my $blackhole;
+	$match = \$blackhole;
+    }
+
+    $$match = "";
+    while(/^[^$characters]/s) {
+	my $submatch = "";
+
+	if(s/^[^$characters\n\t\'\"]*//s) {
+	    $submatch .= $&;
+	}
+
+	if(s/^\'//) {
+	    $submatch .= "\'";
+	    while(/^./ && !s/^\'//) {
+		s/^([^\'\\]*)//s;
+		$submatch .= $1;
+		if(s/^\\//) {
+		    $submatch .= "\\";
+		    if(s/^(.)//s) {
+			$submatch .= $1;
+			if($1 eq "0") {
+			    s/^(\d{0,3})//s;
+			    $submatch .= $1;
+			}
+		    }
+		}
+	    }
+	    $submatch .= "\'";
+
+	    $$match .= $submatch;
+	    $column += length($submatch);
+	} elsif(s/^\"//) {
+	    $submatch .= "\"";
+	    while(/^./ && !s/^\"//) {
+		s/^([^\"\\]*)//s;
+		$submatch .= $1;
+		if(s/^\\//) {
+		    $submatch .= "\\";
+		    if(s/^(.)//s) {
+			$submatch .= $1;
+			if($1 eq "0") {
+			    s/^(\d{0,3})//s;
+			    $submatch .= $1;
+			}
+		    }
+		}
+	    }
+	    $submatch .= "\"";
+
+	    $$match .= $submatch;
+	    $column += length($submatch);
+	} elsif(s/^\n//) {
+	    $submatch .= "\n";
+
+	    $$match .= $submatch;
+	    $line++;
+	    $column = 0;
+	} elsif(s/^\t//) {
+	    $submatch .= "\t";
+
+	    $$match .= $submatch;
+	    $column = $column + 8 - $column % 8;
+	} else {
+	    $$match .= $submatch;
+	    $column += length($submatch);
+	}
+    }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+    return 1;
+}
+
+sub parse_c_block {
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+    my $refstatements = shift;
+    my $refstatements_line = shift;
+    my $refstatements_column = shift;
+
+    local $_ = $$refcurrent;
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    my $statements;
+    if(s/^\{//) {
+	$column++;
+	$statements = "";
+    } else {
+	return 0;
+    }
+
+    parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
+    my $statements_line = $line;
+    my $statements_column = $column;
+
+    my $plevel = 1;
+    while($plevel > 0) {
+	my $match;
+	parse_c_until_one_of("\\{\\}", \$_, \$line, \$column, \$match);
+
+	$column++;
+
+	$statements .= $match;
+	if(s/^\}//) {
+	    $plevel--;
+	    if($plevel > 0) {
+		$statements .= "}";
+	    }
+	} elsif(s/^\{//) {
+	    $plevel++;
+	    $statements .= "{";
+	} else {
+	    return 0;
+	}
+    }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+    $$refstatements = $statements;
+    $$refstatements_line = $statements_line;
+    $$refstatements_column = $statements_column;
+
+    return 1;
+}
+
+sub parse_c_expression {
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+    my $found_function_call_callback = shift;
+
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    local $_ = $$refcurrent;
+
+    parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
+    if(s/^(.*?)(\w+)(\s*)\(//s) {
+	my $begin_line = $line;
+	my $begin_column = $column + length($1) + 1;
+
+	$line = $begin_line;
+	$column = $begin_column + length("$2$3") - 1;
+
+	my $name = $2;
+
+	$_ = "($'";
+
+	# $output->write("$name: $line.$column: '$_'\n");
+
+	my @arguments;
+	my @argument_lines;
+	my @argument_columns;
+	if(!parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
+	    return 0;
+	}
+
+	if($name =~ /^sizeof$/) {
+	    # Nothing
+	} else {
+	    &$found_function_call_callback($begin_line, $begin_column, $line, $column, 
+					   $name, \@arguments);
+	}
+
+	while(defined(my $argument = shift @arguments) &&
+	      defined(my $argument_line = shift @argument_lines) &&
+	      defined(my $argument_column = shift @argument_columns))
+	{
+	    parse_c_expression(\$argument, \$argument_line, \$argument_column, $found_function_call_callback);
+	}
+    } elsif(s/^return//) {
+	$column += length($&);
+	parse_c_until_one_of("\\S", \$_, \$line, \$column);
+	if(!parse_c_expression(\$_, \$line, \$column, $found_function_call_callback)) {
+	    return 0;
+	}
+    } else {
+	return 0;
+    }
+
+    _update_c_position($_, \$line, \$column);
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    return 1;
+}
+
+sub parse_c_statement {
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+    my $found_function_call_callback = shift;
+
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    local $_ = $$refcurrent;
+
+    parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
+    if(s/^(?:case\s+)?(\w+)\s*://) {
+	$column += length($&);
+	parse_c_until_one_of("\\S", \$_, \$line, \$column);
+    }
+
+    # $output->write("$line.$column: '$_'\n");
+
+    if(/^$/) {
+	# Nothing
+    } elsif(/^\{/) {
+	my $statements;
+	my $statements_line;
+	my $statements_column;
+	if(!parse_c_block(\$_, \$line, \$column, \$statements, \$statements_line, \$statements_column)) {
+	    return 0;
+	}
+	if(!parse_c_statements(\$statements, \$statements_line, \$statements_column, $found_function_call_callback)) {
+	    return 0;
+	}
+    } elsif(/^(for|if|switch|while)(\s*)\(/) {
+	$column += length("$1$2");
+	my $name = $1;
+
+	$_ = "($'";
+
+	my @arguments;
+	my @argument_lines;
+	my @argument_columns;
+	if(!parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
+	    return 0;
+	}
+
+	parse_c_until_one_of("\\S", \$_, \$line, \$column);
+	if(!parse_c_statement(\$_, \$line, \$column, $found_function_call_callback)) {
+	    return 0;
+	}
+	parse_c_until_one_of("\\S", \$_, \$line, \$column);
+
+	while(defined(my $argument = shift @arguments) &&
+	      defined(my $argument_line = shift @argument_lines) &&
+	      defined(my $argument_column = shift @argument_columns))
+	{
+	    parse_c_expression(\$argument, \$argument_line, \$argument_column, $found_function_call_callback);
+	}
+    } elsif(s/^else//) {
+	$column += length($&);
+	if(!parse_c_statement(\$_, \$line, \$column, $found_function_call_callback)) {
+	    return 0;
+	}
+    } elsif(parse_c_expression(\$_, \$line, \$column, $found_function_call_callback)) {
+	# Nothing
+    } else {
+	# $output->write("error '$_'\n");
+	# exit 1;
+    }
+
+    _update_c_position($_, \$line, \$column);
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    return 1;
+}
+
+sub parse_c_statements {
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+    my $found_function_call_callback = shift;
+
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    local $_ = $$refcurrent;
+
+    parse_c_until_one_of("\\S", \$_, \$line, \$column);
+    my $statement = "";
+    my $statement_line = $line;
+    my $statement_column = $column;
+
+    my $blevel = 1;
+    my $plevel = 1;
+    while($plevel > 0 || $blevel > 0) {
+	my $match;
+	parse_c_until_one_of("\\(\\)\\[\\]\\{\\};", \$_, \$line, \$column, \$match);
+
+	# $output->write("'$match' '$_'\n");
+
+	$column++;
+	$statement .= $match;
+	if(s/^[\(\[]//) {
+	    $plevel++;
+	    $statement .= $&;
+	} elsif(s/^[\)\]]//) {
+	    $plevel--;
+	    if($plevel <= 0) {
+		$output->write("error $plevel: '$statement' '$match' '$_'\n");
+		exit 1;
+	    }
+	    $statement .= $&;
+	} elsif(s/^\{//) {
+	    $blevel++;
+	    $statement .= $&;
+	} elsif(s/^\}//) {
+	    $blevel--;
+	    $statement .= $&;
+	    if($blevel == 1) {
+		if(!parse_c_statement(\$statement, \$statement_line, \$statement_column, $found_function_call_callback)) {
+		    return 0;
+		}
+		parse_c_until_one_of("\\S", \$_, \$line, \$column);
+		$statement = "";
+		$statement_line = $line;
+		$statement_column = $column;
+	    }
+	} elsif(s/^;//) {
+	    if($plevel == 1 && $blevel == 1) {
+		if(!parse_c_statement(\$statement, \$statement_line, \$statement_column, $found_function_call_callback)) {
+		    return 0;
+		}
+
+		parse_c_until_one_of("\\S", \$_, \$line, \$column);
+		$statement = "";
+		$statement_line = $line;
+		$statement_column = $column;
+	    } else {
+		$statement .= $&;
+	    }
+	} elsif(/^\s*$/ && $statement =~ /^\s*$/ && $match =~ /^\s*$/) {
+	    $plevel = 0;
+	    $blevel = 0;
+	} else {
+	    $output->write("error $plevel: '$statement' '$match' '$_'\n");
+	    exit 1;
+	}
+    }
+
+    _update_c_position($_, \$line, \$column);
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    return 1;
+}
+
+sub parse_c_tuple {
+    my $refcurrent = shift;
+    my $refline = shift;
+    my $refcolumn = shift;
+
+    # FIXME: Should not write directly
+    my $items = shift;
+    my $item_lines = shift;
+    my $item_columns = shift;
+
+    local $_ = $$refcurrent;
+
+    my $line = $$refline;
+    my $column = $$refcolumn;
+
+    my $item;
+    if(s/^\(//) {
+	$column++;
+	$item = "";
+    } else {
+	return 0;
+    }
+
+    my $item_line = $line;
+    my $item_column = $column + 1;
+
+    my $plevel = 1;
+    while($plevel > 0) {
+	my $match;
+	parse_c_until_one_of("\\(,\\)", \$_, \$line, \$column, \$match);
+
+	$column++;
+
+	$item .= $match;
+	if(s/^\)//) {
+	    $plevel--;
+	    if($plevel == 0) {
+		push @$item_lines, $item_line;
+		push @$item_columns, $item_column;
+		push @$items, $item;
+		$item = "";
+	    } else {
+		$item .= ")";
+	    }
+	} elsif(s/^\(//) {
+	    $plevel++;
+	    $item .= "(";
+	} elsif(s/^,//) {
+	    if($plevel == 1) {
+		push @$item_lines, $item_line;
+		push @$item_columns, $item_column;
+		push @$items, $item;
+		parse_c_until_one_of("\\S", \$_, \$line, \$column);
+		$item_line = $line;
+		$item_column = $column + 1;
+		$item = "";
+	    } else {
+		$item .= ",";
+	    }
+	} else {
+	    return 0;
+	}
+    }
+
+    $$refcurrent = $_;
+    $$refline = $line;
+    $$refcolumn = $column;
+
+    return 1;
+}
+
+1;
diff --git a/tools/winapi/function.pm b/tools/winapi/function.pm
index be48873..2bd9b37 100644
--- a/tools/winapi/function.pm
+++ b/tools/winapi/function.pm
@@ -143,6 +143,17 @@
     return $$argument_documentations;
 }
 
+sub statements_line {
+    my $self = shift;
+    my $statements_line = \${$self->{STATEMENTS_LINE}};
+
+    local $_ = shift;
+
+    if(defined($_)) { $$statements_line = $_; }
+    
+    return $$statements_line;
+}
+
 sub statements {
     my $self = shift;
     my $statements = \${$self->{STATEMENTS}};
diff --git a/tools/winapi/make_filter b/tools/winapi/make_filter
index 8278270..4cbd1f3 100755
--- a/tools/winapi/make_filter
+++ b/tools/winapi/make_filter
@@ -38,13 +38,13 @@
 
     if($message) {
 	if($file && $line) {
-	    if($directory && $directory ne ".") {
+	    if($directory && $directory ne "." && $file !~ m%^/%) {
 		$output->write(&file_normalize("$directory/$file") . ":$line: $message\n");
 	    } else {
 		$output->write("$file:$line: $message\n");
 	    }
 	} elsif($file) {
-	    if($directory && $directory ne ".") {
+	    if($directory && $directory ne "." && $file !~ m%^/%) {
 		$output->write(&file_normalize("$directory/$file") . ": $message\n");
 	    } else {
 		$output->write("$file: $message\n");
diff --git a/tools/winapi/make_parser.pm b/tools/winapi/make_parser.pm
index 62e844d..ff0b517 100644
--- a/tools/winapi/make_parser.pm
+++ b/tools/winapi/make_parser.pm
@@ -131,7 +131,7 @@
 	error("line");
     } elsif($tool eq "bison" && /^conflicts:\s+\d+\s+shift\/reduce$/) {
 	# Nothing
-    } elsif($tool eq "gcc" && /^In file included from (.+?):(\d+):$/) {
+    } elsif($tool eq "gcc" && /^(?:In file included |\s*)from (.+?):(\d+)[,:]$/) {
 	# Nothing
     } elsif($tool =~ /^gcc|ld$/ && s/^(.+?\.o(?:\(.*?\))?):\s*//) {
 	ld_output($1, $_)
diff --git a/tools/winapi/winapi_fixup b/tools/winapi/winapi_fixup
index f043138..3583143 100755
--- a/tools/winapi/winapi_fixup
+++ b/tools/winapi/winapi_fixup
@@ -18,14 +18,15 @@
 );
 use output qw($output);
 use winapi_fixup_options qw($options);
-use modules qw($modules);
-use winapi qw($win16api $win32api @winapis);
 
 use type;
-use util;
 use winapi_function;
 use winapi_parser;
 
+use winapi_fixup_documentation qw(&fixup_documentation);
+use winapi_fixup_editor;
+use winapi_fixup_statements qw(&fixup_statements);
+
 my @c_files = $options->c_files;
 @c_files = files_skip(@c_files);
 @c_files = files_filter("winelib", @c_files);
@@ -35,400 +36,38 @@
 my $progress_max = scalar(@c_files);
 
 foreach my $file (@c_files) {
-    my %insert_line;
-    my %substitute_line;
-    my %delete_line;
-
-    my %spec_file;
+    my $editor = new winapi_fixup_editor($file);
 
     $progress_current++;
     if($options->progress) {
-	$output->progress("$file: file $progress_current of $progress_max");
+	$output->progress("$file (file $progress_current of $progress_max)");
     }
 
-    my %documentation_line_used;
-
     my $create_function = sub {
 	return 'winapi_function'->new;
     };
 
     my $found_function = sub {
 	my $function = shift;
-	
-	my $documentation_line = $function->documentation_line;
-	my $documentation = $function->documentation;
-	my $function_line = $function->function_line;
-	my $linkage = $function->linkage;
-	my $return_type = $function->return_type;
-	my $calling_convention = $function->calling_convention;
+
 	my $internal_name = $function->internal_name;
-	my $statements = $function->statements;
-
-	if($linkage eq "static" ||
-	   ($linkage eq "extern" && !defined($statements)) ||
-	   ($linkage eq "" && !defined($statements)))
-	{
-	    return;
+	if($options->progress) {
+	    $output->progress("$file (file $progress_current of $progress_max): $internal_name");
 	}
 
-	my @external_names = $function->external_names;
-	if($#external_names < 0) {
-	    return;
-	}
-
-	if($documentation_line_used{$documentation_line}) {
-	    $documentation = undef;
-	}
-	$documentation_line_used{$documentation_line}++;
-    
 	$output->prefix_callback(sub { return $function->prefix; });
 
-	my @module_ordinal_entries = ();
-	foreach my $entry2 ($function->get_all_module_ordinal) {
-	    (my $external_name2, my $module2, my $ordinal2) = @$entry2;
-	    if(($external_name2 eq "@" ||
-		($win16api->is_module($module2) && !$win16api->is_function_stub_in_module($module2, $external_name2)) ||
-		($win32api->is_module($module2) && !$win32api->is_function_stub_in_module($module2, $external_name2))) &&
-	       $modules->is_allowed_module_in_file($module2, "$current_dir/$file"))
-	    {
-		push @module_ordinal_entries, $entry2; 
-	    }
+	if($options->documentation) {
+	    fixup_documentation($function, $editor);
 	}
 
-	my $spec_modified = 0;
-
-	if($options->stub && defined($documentation)) {
-	    my $calling_convention16 = $function->calling_convention16;
-	    my $calling_convention32 = $function->calling_convention32;
-
-	    foreach my $winapi (@winapis) {
-		my @entries = ();
-		my $module = $winapi->function_internal_module($internal_name);
-		my $ordinal = $winapi->function_internal_ordinal($internal_name);
-
-		if($winapi->is_function_stub_in_module($module, $internal_name)) {
-		    my $external_name = $internal_name;
-		    if($winapi->name eq "win16") {
-			$external_name =~ s/(?:_)?16([AW]?)$//;
-			if(defined($1)) {
-			    $external_name .= $1;
-			}
-		    }
-		    push @entries, [$external_name, $module, $ordinal];
-		}
-
-		foreach (split(/\n/, $documentation)) {
-		    if(/^\s*\*\s*(\S+)\s*[\(\[]\s*(\w+)\s*\.\s*([^\s\)\]]*)\s*[\)\]].*?$/) {
-			my $external_name = $1;
-			my $module = lc($2);
-			my $ordinal = $3;
-
-			if($external_name ne "@" && 
-			   $winapi->is_module($module) &&
-			   $winapi->is_function_stub_in_module($module, $external_name) &&
-			   $internal_name !~ /^\U$module\E_\Q$external_name\E$/)
-			{
-			    push @entries, [$external_name, $module, $ordinal];
-			}
-		    }
-		}
-
-		foreach my $entry (@entries) {
-		    (my $external_name, my $module, my $ordinal) = @$entry;
-
-		    my $refargument_types = $function->argument_types;
-
-		    if(!defined($refargument_types)) {
-			next;
-		    }
-
-		    my $abort = 0;
-		    my $n;
-		    my @argument_kinds = map {
-			my $type = $_;
-			my $kind;
-			if($type ne "..." && !defined($kind = $winapi->translate_argument($type))) {
-			    $output->write("no translation defined: " . $type . "\n");
-			}
-
-			# FIXME: Kludge
-			if(defined($kind) && $kind eq "longlong") {
-			    $n += 2;
-			    ("long", "long");
-			} elsif(defined($kind)) {
-			    $n++;
-			    $kind;
-			} elsif($type eq "...") {
-			    if($winapi->name eq "win16") {
-				$calling_convention16 = "pascal"; # FIXME: Is this correct?
-			    } else {
-				$calling_convention32 = "varargs";
-			    }
-			    ();
-			} else {
-			    $abort = 1;
-			    $n++;
-			    "undef";
-			}
-		    } @$refargument_types;
-
-		    my $substitute = {};
-		    $substitute->{search} = "^\\s*$ordinal\\s+stub\\s+$external_name\\s*(?:#.*?)?\$";
-
-		    if($winapi->name eq "win16") {
-			$substitute->{replace} = "$ordinal $calling_convention16 $external_name(@argument_kinds) $internal_name";
-		    } else {
-			$substitute->{replace} = "$ordinal $calling_convention32 $external_name(@argument_kinds) $internal_name";
-		    }
-
-		    if(!defined($spec_file{$module})) {
-			$spec_file{$module} = [];
-		    }
-
-		    if(!$abort) {
-			$spec_modified = 1;
-			push @{$spec_file{$module}}, $substitute;
-		    }
-		}	    
-	    }
-	}
-
-	my %found_external_names;
-	foreach my $external_name (@external_names) {
-	    $found_external_names{$external_name} = {};
-	}
-
-	my $documentation_modified = 0;
-
-	if(!$spec_modified &&
-	   (defined($documentation) && !$documentation_modified) &&
-	   ($options->documentation_name || $options->documentation_ordinal || 
-	    $options->documentation_missing))
-	{
-	    local $_;
-
-	    my $line3;
-	    my $search;
-	    my $replace;
-
-	    my $count = 0;
-	    my $line2 = $documentation_line - 1;
-	    foreach (split(/\n/, $documentation)) {
-		$line2++;
-		if(/^(\s*\*\s*(\S+)\s*)((?:\s*[\(\[]\s*\w+(?:\s*\.\s*[^\s\)\]]*\s*)?[\)\]])+)(.*?)$/) {
-		    my $part1 = $1;
-		    my $external_name = $2;
-		    my $part3 = $3;
-		    my $part4 = $4;
-
-		    $part4 =~ s/\s*$//;
-
-		    my @entries = ();
-		    while($part3 =~ s/^\s*([\(\[]\s*(\w+)(?:\s*\.\s*([^\s\)\]]*)\s*)?[\)\]])//) {
-			push @entries, [$1, $2, $3];
-		    }
-
-		    my $found = 0;
-		    foreach my $external_name2 (@external_names) {
-			if($external_name eq $external_name2) {
-			    foreach my $entry (@entries) {
-				(undef, my $module, undef) = @$entry;
-				$found_external_names{$external_name2}{$module} = 1;
-			    }
-			    $found = 1;
-			    last;
-			}
-		    }
-
-		    my $replaced = 0;
-		    my $replace2 = "";
-		    foreach my $entry (@entries) {
-			my $part12 = $part1;
-			(my $part32, my $module, my $ordinal) = @$entry;
-
-			foreach my $entry2 (@module_ordinal_entries) {
-			    (my $external_name2, my $module2, my $ordinal2) = @$entry2;
-
-			    if($options->documentation_name && lc($module) eq $module2 && 
-			       $external_name ne $external_name2) 
-			    {
-				if(!$found && $part12 =~ s/\b\Q$external_name\E\b/$external_name2/) {
-				    $external_name = $external_name2;
-				    $replaced++;
-				}
-			    }
-
-			    if($options->documentation_ordinal &&
-			       $external_name eq $external_name2 &&
-			       lc($module) eq $module2 && 
-			       ($#entries > 0 || !defined($ordinal) || ($ordinal ne $ordinal2)))
-			    {
-				if(defined($ordinal)) {
-				    if($part32 =~ s/\Q$module\E\s*.\s*\Q$ordinal\E/\U$module2\E.$ordinal2/ || $#entries > 0) {
-					$replaced++;
-				    }
-				} else {
-				    if($part32 =~ s/\Q$module\E/\U$module2\E.$ordinal2/ || $#entries > 0) {
-					$replaced++;
-				    }
-				}
-			    }
-
-			}
-			if($replace2) { $replace2 .= "\n"; }
-			$replace2 .= "$part12$part32$part4";
-		    }
-
-		    if($replaced > 0) {
-			$line3 = $line2;
-			$search = "^\Q$_\E\$";
-			$replace = $replace2;
-		    }
-		    $count++;
-		} elsif(/^(\s*\*\s*)([^\s\(]+)(?:\(\))?\s*$/) {
-		    my $part1 = $1;
-		    my $external_name = $2;
-
-		    if($internal_name =~ /^(?:\S+_)?\Q$external_name\E(?:16)?$/) {
-			foreach my $entry (@module_ordinal_entries) {
-			    (my $external_name2, my $module, my $ordinal) = @$entry;
-
-			    $line3 = $line2;
-			    $search = "^\Q$_\E\$";
-			    $replace = "$part1$external_name2 (\U$module\E.$ordinal)";
-			}
-			$count++;
-		    }
-		}
-	    }
-
-	    if(defined($line3) && defined($search) && defined($replace)) {
-		if($count > 1 || $#external_names >= 1) {
-		    $output->write("multiple entries (fixup not supported)\n");
-		    # $output->write("s/$search/$replace/\n");
-		    # $output->write("@external_names\n");
-		} else {
-		    $documentation_modified = 1;
-
-		    $substitute_line{$line3}{search} = $search;
-		    $substitute_line{$line3}{replace} = $replace;
-		    
-		}
-	    }
-	}
-
-	if(!$spec_modified && !$documentation_modified &&
-	   $options->documentation_missing && defined($documentation))
-	{
-	    my $part1;
-	    my $part2;
-	    my $part3;
-	    my $part4;
-	    my $line3 = 0;
-	    
-	    my $line2 = $documentation_line - 1;
-	    foreach (split(/\n/, $documentation)) {
-		$line2++;
-		if(/^(\s*\*\s*)(\S+\s*)([\(\[])\s*\w+\s*\.\s*[^\s\)\]]*\s*([\)\]]).*?$/) {
-		    $part1 = $1;
-		    $part2 = $2;
-		    $part3 = $3;
-		    $part4 = $4;
-
-		    $part2 =~ s/\S/ /g;
-
-		    $line3 = $line2 + 1;
-		}
-	    }
-
-	    foreach my $entry2 (@module_ordinal_entries) {
-		(my $external_name2, my $module2, my $ordinal2) = @$entry2;
-
-		my $found = 0;
-		foreach my $external_name (keys(%found_external_names)) {
-		    foreach my $module3 (keys(%{$found_external_names{$external_name}})) {
-			if($external_name eq $external_name2 && uc($module2) eq $module3) {
-			    $found = 1;
-			}
-		    }
-		}
-		# FIXME: Not 100% correct
-		if(!$found && 
-		   !$win16api->is_function_stub_in_module($module2, $internal_name) && 
-		   !$win32api->is_function_stub_in_module($module2, $internal_name)) 
-		{
-		    if($line3 > 0) {
-			$documentation_modified = 1;
-
-			$part2 = $external_name2 . " " x (length($part2) - length($external_name2));
-			$insert_line{$line3} = "$part1$part2$part3\U$module2\E.$ordinal2$part4\n";
-		    } else {
-			$output->write("$external_name2 (\U$module2\E.$ordinal2) missing (fixup not supported)\n");
-		    }
-		}
-	    }
-	}
-
-	if(!$documentation_modified && 
-	   defined($documentation) &&
-	   $options->documentation_wrong)
-	{
-	    my $line2 = $documentation_line - 1;
-	    foreach (split(/\n/, $documentation)) {
-		$line2++;
-		if(/^\s*\*\s*(\S+)\s*[\(\[]\s*(\w+)\s*\.\s*([^\s\)\]]*)\s*[\)\]].*?$/) {
-		    my $external_name = $1;
-		    my $module = $2;
-		    my $ordinal = $3;
-
-		    my $found = 0;
-		    foreach my $entry2 (@module_ordinal_entries) {
-			(my $external_name2, my $module2, my $ordinal2) = @$entry2;
-
-			if($external_name eq $external_name2 &&
-			   lc($module) eq $module2 &&
-			   $ordinal eq $ordinal2) 
-			{
-			    $found = 1;
-			}
-		    }
-		    if(!$found) {
-			if(1) {
-			    $documentation_modified = 1;
-
-			    $delete_line{$line2} = "^\Q$_\E\$";
-			} else {
-			    $output->write("$external_name (\U$module\E.$ordinal) wrong (fixup not supported)\n");
-			};
-		    }
-		}
-	    }
-	}
-
-	if(!$spec_modified && !$documentation_modified && !defined($documentation))
-	{
-	    my $insert = "";
-	    foreach my $winapi (@winapis) {
-		my $external_name = $winapi->function_external_name($internal_name);
-		my $module = $winapi->function_internal_module($internal_name);
-		my $ordinal = $winapi->function_internal_ordinal($internal_name);
-
-		if(defined($external_name) && defined($module) && defined($ordinal)) {
-		    $insert .= " *\t\t$external_name (\U$module\E.$ordinal)\n";
-		}
-	    }
-	    if($insert) {
-		$insert_line{$function_line} = 
-		    "/" . "*" x 71 . "\n" .
-		    "$insert" .
-		    " */\n";
-	    }
+	if($options->statements) {
+	    fixup_statements($function, $editor);
 	}
 
 	$output->prefix("");
     };
 
-
     my $create_type = sub {
 	return 'type'->new;
     };
@@ -444,160 +83,6 @@
 
     &winapi_parser::parse_c_file($file, $create_function, $found_function, $create_type, $found_type, $found_preprocessor);
 
-    my $editor = sub {
-	local *IN = shift;
-	local *OUT = shift;
-
-	my $modified = 0;
-	while(<IN>) {
-	    chomp;
-
-	    my $line;
-
-	    $line = $insert_line{$.};
-	    if(defined($line)) {
-		if($options->modify) {
-		    $_ = "$line$_";
-		    $modified = 1;
-		} else {
-		    my $line2 = $line; chomp($line2);
-		    my @line2 = split(/\n/, $line2);
-		    if($#line2 > 0) {
-			$output->write("$file: $.: insert: \\\n");
-			foreach my $line2 (@line2) {
-			    $output->write("'$line2'\n");
-			}
-		    } else {
-			$output->write("$file: $.: insert: '$line2'\n");
-		    }
-		}
-	    }
-
-	    my $search = $substitute_line{$.}{search};
-	    my $replace = $substitute_line{$.}{replace};
-	    
-	    if(defined($search) && defined($replace)) {
-		my $modified2 = 0;
-		if(s/$search/$replace/) {
-		    if($options->modify) {
-			$modified = 1;
-		    }
-		    $modified2 = 1;
-		}
-
-		if(!$options->modify || !$modified2) {
-		    my $search2;
-		    my $replace2;
-		    if(!$modified2) {
-			$search2 = "unmatched search"; 
-			$replace2 = "unmatched replace"; 
-		    } else {
-			$search2 = "search"; 
-			$replace2 = "replace";
-		    }
-		    $output->write("$file: $.: $search2 : '$search'\n");
-		    
-		    my @replace2 = split(/\n/, $replace);
-		    if($#replace2 > 0) {
-			$output->write("$file: $.: $replace2: \\\n");
-			foreach my $replace2 (@replace2) {
-			    $output->write("'$replace2'\n");
-			}
-		    } else {
-			$output->write("$file: $.: $replace2: '$replace'\n");
-		    }
-		}
-	    }
-
-	    $line = $delete_line{$.};
-	    if(defined($line)) {
-		if(/$line/) {
-		    if($options->modify) {
-			$modified = 1;
-			next;
-		    } else {
-			$output->write("$file: $.: delete: '$line'\n");
-		    }
-		} else {
-		    $output->write("$file: $.: unmatched delete: '$line'\n");
-		}
-	    }
-
-	    print OUT "$_\n";
-	}
-
-	return $modified;
-    };
-
-    my $n = 0;
-    while(defined(each %insert_line)) { $n++; }
-    while(defined(each %substitute_line)) { $n++; }
-    while(defined(each %delete_line)) { $n++; }
-    if($n > 0) {
-	edit_file($file, $editor);
-    }
-
-    foreach my $module (sort(keys(%spec_file))) {
-	my $file; 
-	foreach my $winapi (@winapis) {
-	    $file = ($winapi->module_file($module) || $file);
-	}
-
-	if(defined($file)) {
-	    $file = file_normalize($file);
-	}
-
-	my @substitutes = @{$spec_file{$module}};
-
-	my $editor = sub {
-	    local *IN = shift;
-	    local *OUT = shift;
-	    
-	    my $modified = 0;
-	    while(<IN>) {
-		chomp;
-
-		my @substitutes2 = ();
-		foreach my $substitute (@substitutes) {
-		    my $search = $substitute->{search};
-		    my $replace = $substitute->{replace};
-
-		    if(s/$search/$replace/) {
-			if($options->modify) {
-			    $modified = 1;
-			} else {
-			    $output->write("$file: search : '$search'\n");
-			    $output->write("$file: replace: '$replace'\n");
-			}
-			next;
-		    } else {
-			push @substitutes2, $substitute;
-		    }
-		}
-		@substitutes = @substitutes2;
-
-		print OUT "$_\n";
-	    }
-	    
-	    return $modified;
-	};
-
-	if(defined($file)) {
-	    edit_file($file, $editor);
-	} else {
-	    $output->write("$module: doesn't have any spec file\n");
-	}
-
-	if($#substitutes >= 0) {
-	    foreach my $substitute (@substitutes) {
-		my $search = $substitute->{search};
-		my $replace = $substitute->{replace};
-
-		$output->write("$file: unmatched search : '$search'\n");
-		$output->write("$file: unmatched replace: '$replace'\n");
-	    }
-	}
-
-    }
+    $editor->flush;
 }
 
diff --git a/tools/winapi/winapi_fixup_documentation.pm b/tools/winapi/winapi_fixup_documentation.pm
new file mode 100644
index 0000000..15d22ea
--- /dev/null
+++ b/tools/winapi/winapi_fixup_documentation.pm
@@ -0,0 +1,384 @@
+package winapi_fixup_documentation;
+
+use strict;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+require Exporter;
+
+@ISA = qw(Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw(&fixup_documentation);
+
+use config qw($current_dir $wine_dir);
+use modules qw($modules);
+use options qw($options);
+use output qw($output);
+use winapi qw($win16api $win32api @winapis);
+
+my %documentation_line_used;
+
+sub fixup_documentation {
+    my $function = shift;
+    my $editor = shift;
+
+    my $file = $function->file;
+    my $documentation_line = $function->documentation_line;
+    my $documentation = $function->documentation;
+    my $function_line = $function->function_line;
+    my $linkage = $function->linkage;
+    my $return_type = $function->return_type;
+    my $calling_convention = $function->calling_convention;
+    my $internal_name = $function->internal_name;
+    my $statements = $function->statements;
+    
+    if($linkage eq "static" ||
+       ($linkage eq "extern" && !defined($statements)) ||
+       ($linkage eq "" && !defined($statements)))
+    {
+	return;
+    }
+    
+    my @external_names = $function->external_names;
+    if($#external_names < 0) {
+	return;
+    }
+
+    if($documentation_line_used{$file}{documentation_line}) {
+	$documentation = undef;
+    }
+    $documentation_line_used{$file}{$documentation_line}++;
+    
+    my @module_ordinal_entries = ();
+    foreach my $entry2 ($function->get_all_module_ordinal) {
+	(my $external_name2, my $module2, my $ordinal2) = @$entry2;
+	if(($external_name2 eq "@" ||
+	    ($win16api->is_module($module2) && !$win16api->is_function_stub_in_module($module2, $external_name2)) ||
+	    ($win32api->is_module($module2) && !$win32api->is_function_stub_in_module($module2, $external_name2))) &&
+	       $modules->is_allowed_module_in_file($module2, "$current_dir/$file"))
+	{
+	    push @module_ordinal_entries, $entry2; 
+	}
+    }
+    
+    my $spec_modified = 0;
+    
+    if($options->stub && defined($documentation)) {
+	my $calling_convention16 = $function->calling_convention16;
+	my $calling_convention32 = $function->calling_convention32;
+	
+	foreach my $winapi (@winapis) {
+	    my @entries = ();
+	    my $module = $winapi->function_internal_module($internal_name);
+	    my $ordinal = $winapi->function_internal_ordinal($internal_name);
+	    
+	    if($winapi->is_function_stub_in_module($module, $internal_name)) {
+		my $external_name = $internal_name;
+		if($winapi->name eq "win16") {
+		    $external_name =~ s/(?:_)?16([AW]?)$//;
+		    if(defined($1)) {
+			$external_name .= $1;
+		    }
+		}
+		push @entries, [$external_name, $module, $ordinal];
+	    }
+	    
+	    foreach (split(/\n/, $documentation)) {
+		if(/^\s*\*\s*(\S+)\s*[\(\[]\s*(\w+)\s*\.\s*([^\s\)\]]*)\s*[\)\]].*?$/) {
+		    my $external_name = $1;
+		    my $module = lc($2);
+		    my $ordinal = $3;
+		    
+		    if($external_name ne "@" && 
+		       $winapi->is_module($module) &&
+		       $winapi->is_function_stub_in_module($module, $external_name) &&
+		       $internal_name !~ /^\U$module\E_\Q$external_name\E$/)
+		    {
+			push @entries, [$external_name, $module, $ordinal];
+		    }
+		}
+	    }
+	    
+	    foreach my $entry (@entries) {
+		(my $external_name, my $module, my $ordinal) = @$entry;
+		
+		my $refargument_types = $function->argument_types;
+		
+		if(!defined($refargument_types)) {
+		    next;
+		}
+		
+		my $abort = 0;
+		my $n;
+		my @argument_kinds = map {
+		    my $type = $_;
+		    my $kind;
+		    if($type ne "..." && !defined($kind = $winapi->translate_argument($type))) {
+			$output->write("no translation defined: " . $type . "\n");
+		    }
+		    
+		    # FIXME: Kludge
+		    if(defined($kind) && $kind eq "longlong") {
+			$n += 2;
+			("long", "long");
+		    } elsif(defined($kind)) {
+			$n++;
+			$kind;
+		    } elsif($type eq "...") {
+			if($winapi->name eq "win16") {
+			    $calling_convention16 = "pascal"; # FIXME: Is this correct?
+			} else {
+			    $calling_convention32 = "varargs";
+			}
+			();
+		    } else {
+			$abort = 1;
+			$n++;
+			"undef";
+		    }
+		} @$refargument_types;
+		
+		my $search = "^\\s*$ordinal\\s+stub\\s+$external_name\\s*(?:#.*?)?\$";
+		my $replace;
+		if($winapi->name eq "win16") {
+		    $replace = "$ordinal $calling_convention16 $external_name(@argument_kinds) $internal_name";
+		} else {
+		    $replace = "$ordinal $calling_convention32 $external_name(@argument_kinds) $internal_name";
+		}
+
+		if(!$abort) {
+		    $spec_modified = 1;
+		    $editor->replace_spec_file($module, $search, $replace);
+		}
+	    }	    
+	}
+    }
+    
+    my %found_external_names;
+    foreach my $external_name (@external_names) {
+	$found_external_names{$external_name} = {};
+    }
+    
+    my $documentation_modified = 0;
+    
+    if(!$spec_modified &&
+       (defined($documentation) && !$documentation_modified) &&
+       ($options->documentation_name || $options->documentation_ordinal || 
+	$options->documentation_missing))
+    {
+	local $_;
+	
+	my $line3;
+	my $search;
+	my $replace;
+	
+	my $count = 0;
+	my $line2 = $documentation_line - 1;
+	foreach (split(/\n/, $documentation)) {
+	    $line2++;
+	    if(/^(\s*\*\s*(\S+)\s*)((?:\s*[\(\[]\s*\w+(?:\s*\.\s*[^\s\)\]]*\s*)?[\)\]])+)(.*?)$/) {
+		my $part1 = $1;
+		my $external_name = $2;
+		my $part3 = $3;
+		my $part4 = $4;
+		
+		$part4 =~ s/\s*$//;
+		
+		my @entries = ();
+		while($part3 =~ s/^\s*([\(\[]\s*(\w+)(?:\s*\.\s*([^\s\)\]]*)\s*)?[\)\]])//) {
+		    push @entries, [$1, $2, $3];
+		}
+		
+		my $found = 0;
+		foreach my $external_name2 (@external_names) {
+		    if($external_name eq $external_name2) {
+			foreach my $entry (@entries) {
+			    (undef, my $module, undef) = @$entry;
+			    $found_external_names{$external_name2}{$module} = 1;
+			}
+			$found = 1;
+			last;
+			}
+		}
+		
+		my $replaced = 0;
+		my $replace2 = "";
+		foreach my $entry (@entries) {
+		    my $part12 = $part1;
+		    (my $part32, my $module, my $ordinal) = @$entry;
+		    
+		    foreach my $entry2 (@module_ordinal_entries) {
+			(my $external_name2, my $module2, my $ordinal2) = @$entry2;
+			
+			if($options->documentation_name && lc($module) eq $module2 && 
+			   $external_name ne $external_name2) 
+			{
+			    if(!$found && $part12 =~ s/\b\Q$external_name\E\b/$external_name2/) {
+				$external_name = $external_name2;
+				$replaced++;
+			    }
+			}
+			
+			if($options->documentation_ordinal &&
+			   $external_name eq $external_name2 &&
+			   lc($module) eq $module2 && 
+			   ($#entries > 0 || !defined($ordinal) || ($ordinal ne $ordinal2)))
+			{
+			    if(defined($ordinal)) {
+				if($part32 =~ s/\Q$module\E\s*.\s*\Q$ordinal\E/\U$module2\E.$ordinal2/ || $#entries > 0) {
+				    $replaced++;
+				}
+			    } else {
+				if($part32 =~ s/\Q$module\E/\U$module2\E.$ordinal2/ || $#entries > 0) {
+				    $replaced++;
+				}
+			    }
+			}
+		    }
+		    if($replace2) { $replace2 .= "\n"; }
+		    $replace2 .= "$part12$part32$part4";
+		}
+		
+		if($replaced > 0) {
+		    $line3 = $line2;
+		    $search = "^\Q$_\E\$";
+		    $replace = $replace2;
+		}
+		$count++;
+	    } elsif(/^(\s*\*\s*)([^\s\(]+)(?:\(\))?\s*$/) {
+		my $part1 = $1;
+		my $external_name = $2;
+
+		if($internal_name =~ /^(?:\S+_)?\Q$external_name\E(?:16)?$/) {
+		    foreach my $entry (@module_ordinal_entries) {
+			(my $external_name2, my $module, my $ordinal) = @$entry;
+
+			$line3 = $line2;
+			$search = "^\Q$_\E\$";
+			$replace = "$part1$external_name2 (\U$module\E.$ordinal)";
+		    }
+		    $count++;
+		}
+	    }
+	}
+
+	if(defined($line3) && defined($search) && defined($replace)) {
+	    if($count > 1 || $#external_names >= 1) {
+		$output->write("multiple entries (fixup not supported)\n");
+		# $output->write("s/$search/$replace/\n");
+		# $output->write("@external_names\n");
+	    } else {
+		$documentation_modified = 1;
+		$editor->substitute_line($line3, $search, $replace);
+	    }
+	}
+    }
+
+    if(!$spec_modified && !$documentation_modified &&
+       $options->documentation_missing && defined($documentation))
+    {
+	my $part1;
+	my $part2;
+	my $part3;
+	my $part4;
+	my $line3 = 0;
+	
+	my $line2 = $documentation_line - 1;
+	foreach (split(/\n/, $documentation)) {
+	    $line2++;
+	    if(/^(\s*\*\s*)(\S+\s*)([\(\[])\s*\w+\s*\.\s*[^\s\)\]]*\s*([\)\]]).*?$/) {
+		$part1 = $1;
+		$part2 = $2;
+		$part3 = $3;
+		$part4 = $4;
+
+		$part2 =~ s/\S/ /g;
+		
+		$line3 = $line2 + 1;
+	    }
+	}
+
+	foreach my $entry2 (@module_ordinal_entries) {
+	    (my $external_name2, my $module2, my $ordinal2) = @$entry2;
+	    
+	    my $found = 0;
+	    foreach my $external_name (keys(%found_external_names)) {
+		foreach my $module3 (keys(%{$found_external_names{$external_name}})) {
+		    if($external_name eq $external_name2 && uc($module2) eq $module3) {
+			$found = 1;
+		    }
+		}
+	    }
+	    # FIXME: Not 100% correct
+	    if(!$found && 
+	       !$win16api->is_function_stub_in_module($module2, $internal_name) && 
+	       !$win32api->is_function_stub_in_module($module2, $internal_name)) 
+	    {
+		if($line3 > 0) {
+		    $documentation_modified = 1;
+		    $part2 = $external_name2 . " " x (length($part2) - length($external_name2));
+		    $editor->insert_line($line3, "$part1$part2$part3\U$module2\E.$ordinal2$part4\n");
+		} else {
+		    $output->write("$external_name2 (\U$module2\E.$ordinal2) missing (fixup not supported)\n");
+		}
+	    }
+	}
+    }
+
+    if(!$documentation_modified && 
+       defined($documentation) &&
+       $options->documentation_wrong)
+    {
+	my $line2 = $documentation_line - 1;
+	foreach (split(/\n/, $documentation)) {
+	    $line2++;
+	    if(/^\s*\*\s*(\S+)\s*[\(\[]\s*(\w+)\s*\.\s*([^\s\)\]]*)\s*[\)\]].*?$/) {
+		my $external_name = $1;
+		my $module = $2;
+		my $ordinal = $3;
+		
+		my $found = 0;
+		foreach my $entry2 (@module_ordinal_entries) {
+		    (my $external_name2, my $module2, my $ordinal2) = @$entry2;
+		    
+		    if($external_name eq $external_name2 &&
+		       lc($module) eq $module2 &&
+		       $ordinal eq $ordinal2) 
+		    {
+			$found = 1;
+		    }
+		}
+		if(!$found) {
+		    if(1) {
+			$documentation_modified = 1;
+
+			$editor->delete_line($line2, "^\Q$_\E\$");
+		    } else {
+			$output->write("$external_name (\U$module\E.$ordinal) wrong (fixup not supported)\n");
+		    };
+		}
+	    }
+	}
+    }
+
+    if(!$spec_modified && !$documentation_modified && !defined($documentation))
+    {
+	my $insert = "";
+	foreach my $winapi (@winapis) {
+	    my $external_name = $winapi->function_external_name($internal_name);
+	    my $module = $winapi->function_internal_module($internal_name);
+	    my $ordinal = $winapi->function_internal_ordinal($internal_name);
+
+	    if(defined($external_name) && defined($module) && defined($ordinal)) {
+		$insert .= " *\t\t$external_name (\U$module\E.$ordinal)\n";
+	    }
+	}
+	if($insert) {
+	    $editor->insert_line($function_line,
+				 "/" . "*" x 71 . "\n" .
+				 "$insert" .
+				 " */\n");
+	}
+    }
+}
+
+1;
diff --git a/tools/winapi/winapi_fixup_editor.pm b/tools/winapi/winapi_fixup_editor.pm
new file mode 100644
index 0000000..89331b4
--- /dev/null
+++ b/tools/winapi/winapi_fixup_editor.pm
@@ -0,0 +1,389 @@
+package winapi_fixup_editor;
+
+use strict;
+
+use options qw($options);
+use output qw($output);
+use winapi qw($win16api $win32api @winapis);
+
+use util;
+
+sub new {
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+    my $self  = {};
+    bless ($self, $class);
+
+    my $file = \${$self->{FILE}};
+
+    $$file = shift;
+
+    return $self;
+}
+
+sub add_trigger {
+    my $self = shift;
+
+    my $triggers = \%{$self->{TRIGGERS}};
+
+    my $line = shift;
+    my $action = shift;
+
+    if(!defined($$triggers{$line})) {
+	$$triggers{$line} = [];
+    }
+
+    push @{$$triggers{$line}}, $action;
+}
+
+sub replace {
+    my $self = shift;
+
+    my $begin_line = shift;
+    my $begin_column = shift;
+    my $end_line = shift;
+    my $end_column = shift;
+    my $replace = shift;
+
+    my $file = \${$self->{FILE}};
+    
+    my $line = $begin_line;
+    my $action = {};
+
+    $self->add_trigger($begin_line, {
+	type => "replace",
+	begin_line => $begin_line,
+	begin_column => $begin_column,
+	end_line => $end_line,
+	end_column => $end_column,
+	replace => $replace
+    });
+}
+
+sub flush {
+    my $self = shift;
+
+    my $file = \${$self->{FILE}};
+    my $triggers = \%{$self->{TRIGGERS}};
+
+    my $editor = sub {
+	local *IN = shift;
+	local *OUT = shift;
+
+	my $modified = 0;
+
+	my $again = 0;
+	my $lookahead = 0;
+	my $lookahead_count = 0;
+	LINE: while($again || defined(my $current = <IN>)) {
+	    if(!$again) {
+		chomp $current;
+
+		if($lookahead) {
+		    $lookahead = 0;
+		    $_ .= "\n" . $current;
+		    $lookahead_count++;
+		} else {
+		    $_ = $current;
+		    $lookahead_count = 0;
+		}
+	    } else {
+		$lookahead_count = 0;
+		$again = 0;
+	    }
+
+	    my $line = $. - $lookahead_count;
+	    foreach my $action (@{$$triggers{$line}}) {
+		if($. < $action->{end_line}) {
+		    $lookahead = 1;
+		    next LINE;
+		}
+
+		my $type = $action->{type};
+		my $begin_line = $action->{begin_line};
+		my $begin_column = $action->{begin_column};
+		my $end_line = $action->{end_line};
+		my $end_column = $action->{end_column};
+
+		if($type eq "replace") {
+		    my $replace = $action->{replace};
+
+		    my @lines = split(/\n/, $_);
+		    if($#lines < 0) {
+			@lines = ($_);
+		    }
+
+		    my $begin = "";
+		    my $column = 0;
+		    $_ = $lines[0];
+		    while($column < $begin_column - 1 && s/^.//) {
+			$begin .= $&;
+			if($& eq "\t") {
+			    $column = $column + 8 - $column % 8;
+			} else {
+			    $column++;
+			}
+		    }
+
+		    my $column2 = 0;
+		    $_ = $lines[$#lines];
+		    while($column2 < $end_column && s/^.//) {
+			if($& eq "\t") {
+			    $column2 = $column2 + 8 - $column2 % 8;
+			} else {
+			    $column2++;
+			}
+		    }
+		    my $end = $_;
+
+		    $_ = "$begin$replace$end";
+		    if($options->modify) {
+			$modified = 1;
+		    } else {
+			$output->write("$$file:$begin_line.$begin_column-$end_line.$end_column: $replace\n");
+		    }
+		}
+	    }
+
+	    print OUT "$_\n";
+	}
+
+	return $modified;
+    };
+
+    my $modified = 0;
+    if(1) {
+	$modified = edit_file($$file, $editor);
+    }
+
+    if(!$modified) {
+	$self->flush_old;
+    }
+}
+
+########################################################################
+# Hack for backward compabillity
+#
+
+my %insert_line;
+my %substitute_line;
+my %delete_line;
+
+my %spec_file;
+
+sub flush_old {
+    my $self = shift;
+
+    my $file = ${$self->{FILE}};
+
+    my $editor = sub {
+	local *IN = shift;
+	local *OUT = shift;
+
+	my $modified = 0;
+	while(<IN>) {
+	    chomp;
+
+	    my $line;
+
+	    $line = $insert_line{$.};
+	    if(defined($line)) {
+		if($options->modify) {
+		    $_ = "$line$_";
+		    $modified = 1;
+		} else {
+		    my $line2 = $line; chomp($line2);
+		    my @line2 = split(/\n/, $line2);
+		    if($#line2 > 0) {
+			$output->write("$file: $.: insert: \\\n");
+			foreach my $line2 (@line2) {
+			    $output->write("'$line2'\n");
+			}
+		    } else {
+			$output->write("$file: $.: insert: '$line2'\n");
+		    }
+		}
+	    }
+
+	    my $search = $substitute_line{$.}{search};
+	    my $replace = $substitute_line{$.}{replace};
+	    
+	    if(defined($search) && defined($replace)) {
+		my $modified2 = 0;
+		if(s/$search/$replace/) {
+		    if($options->modify) {
+			$modified = 1;
+		    }
+		    $modified2 = 1;
+		}
+
+		if(!$options->modify || !$modified2) {
+		    my $search2;
+		    my $replace2;
+		    if(!$modified2) {
+			$search2 = "unmatched search"; 
+			$replace2 = "unmatched replace"; 
+		    } else {
+			$search2 = "search"; 
+			$replace2 = "replace";
+		    }
+		    $output->write("$file: $.: $search2 : '$search'\n");
+		    
+		    my @replace2 = split(/\n/, $replace);
+		    if($#replace2 > 0) {
+			$output->write("$file: $.: $replace2: \\\n");
+			foreach my $replace2 (@replace2) {
+			    $output->write("'$replace2'\n");
+			}
+		    } else {
+			$output->write("$file: $.: $replace2: '$replace'\n");
+		    }
+		}
+	    }
+
+	    $line = $delete_line{$.};
+	    if(defined($line)) {
+		if(/$line/) {
+		    if($options->modify) {
+			$modified = 1;
+			next;
+		    } else {
+			$output->write("$file: $.: delete: '$line'\n");
+		    }
+		} else {
+		    $output->write("$file: $.: unmatched delete: '$line'\n");
+		}
+	    }
+
+	    print OUT "$_\n";
+	}
+
+	return $modified;
+    };
+
+    my $n = 0;
+    while(defined(each %insert_line)) { $n++; }
+    while(defined(each %substitute_line)) { $n++; }
+    while(defined(each %delete_line)) { $n++; }
+    if($n > 0) {
+	edit_file($file, $editor);
+    }
+
+    foreach my $module (sort(keys(%spec_file))) {
+	my $file; 
+	foreach my $winapi (@winapis) {
+	    $file = ($winapi->module_file($module) || $file);
+	}
+
+	if(defined($file)) {
+	    $file = file_normalize($file);
+	}
+
+	my @substitutes = @{$spec_file{$module}};
+
+	my $editor = sub {
+	    local *IN = shift;
+	    local *OUT = shift;
+	    
+	    my $modified = 0;
+	    while(<IN>) {
+		chomp;
+
+		my @substitutes2 = ();
+		foreach my $substitute (@substitutes) {
+		    my $search = $substitute->{search};
+		    my $replace = $substitute->{replace};
+
+		    if(s/$search/$replace/) {
+			if($options->modify) {
+			    $modified = 1;
+			} else {
+			    $output->write("$file: search : '$search'\n");
+			    $output->write("$file: replace: '$replace'\n");
+			}
+			next;
+		    } else {
+			push @substitutes2, $substitute;
+		    }
+		}
+		@substitutes = @substitutes2;
+
+		print OUT "$_\n";
+	    }
+	    
+	    return $modified;
+	};
+
+	if(defined($file)) {
+	    edit_file($file, $editor);
+	} else {
+	    $output->write("$module: doesn't have any spec file\n");
+	}
+
+	if($#substitutes >= 0) {
+	    foreach my $substitute (@substitutes) {
+		my $search = $substitute->{search};
+		my $replace = $substitute->{replace};
+
+		$output->write("$file: unmatched search : '$search'\n");
+		$output->write("$file: unmatched replace: '$replace'\n");
+	    }
+	}
+
+    }
+
+    %insert_line = ();
+    %substitute_line = ();
+    %delete_line = ();
+
+    %spec_file = ();
+}
+
+sub delete_line {
+    my $self = shift;
+
+    my $line = shift;
+    my $pattern = shift;
+    
+    $delete_line{$line} = $pattern;
+}
+
+sub insert_line {
+    my $self = shift;
+
+    my $line = shift;
+    my $insert = shift;
+    
+    $insert_line{$line} = $insert;
+}
+
+sub substitute_line {
+    my $self = shift;
+
+    my $line = shift;
+    my $search = shift;
+    my $replace = shift;
+    
+    $substitute_line{$line}{search} = $search;
+    $substitute_line{$line}{replace} = $replace;
+}
+
+sub replace_spec_file {
+    my $self = shift;
+
+    my $module = shift;
+    my $search = shift;
+    my $replace = shift;
+    
+    my $substitute = {};
+    $substitute->{search} = $search;
+    $substitute->{replace} = $replace;
+    
+    if(!defined($spec_file{$module})) {
+	$spec_file{$module} = [];
+    }
+    
+    push @{$spec_file{$module}}, $substitute;
+}
+
+1;
diff --git a/tools/winapi/winapi_fixup_options.pm b/tools/winapi/winapi_fixup_options.pm
index e2a26dd..2acc704 100644
--- a/tools/winapi/winapi_fixup_options.pm
+++ b/tools/winapi/winapi_fixup_options.pm
@@ -28,6 +28,8 @@
     "documentation-name" => { default => 1, parent => "documentation", description => "documentation name fixup" },
     "documentation-ordinal" => { default => 1, parent => "documentation", description => "documentation ordinal fixup" },
     "documentation-wrong" => { default => 1, parent => "documentation", description => "documentation wrong fixup" },
+    "statements" => { default => 1, parent => "local", description => "statements fixup" },
+    "statements-windowsx" => { default => 1, parent => "local", description => "statements windowsx fixup" },
     "stub" => { default => 0, parent => "local", description => "stub fixup" },
 
     "global" => { default => 1, description => "global fixup" },
diff --git a/tools/winapi/winapi_fixup_statements.pm b/tools/winapi/winapi_fixup_statements.pm
new file mode 100644
index 0000000..f7706db
--- /dev/null
+++ b/tools/winapi/winapi_fixup_statements.pm
@@ -0,0 +1,198 @@
+package winapi_fixup_statements;
+
+use strict;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
+require Exporter;
+
+@ISA = qw(Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw(&fixup_statements);
+
+use options qw($options);
+use output qw($output);
+
+use c_parser;
+
+sub fixup_function_call {
+    my $name = shift;
+    my @arguments = @{(shift)};;
+
+    return "$name(" . join(", ", @arguments) . ")";
+}
+
+sub _parse_makelong {
+    my $value = shift;
+
+    my $low;
+    my $high;
+    if($value =~ /^
+       (?:\(\w+\)\s*)?
+       MAKE(?:LONG|LPARAM|LRESULT|WPARAM)\s*
+       \(\s*(.*?)\s*,\s*(.*?)\s*\)$/sx)
+    {
+	$low = $1;
+	$high = $2;
+    } elsif($value =~ /^(?:\(\w+\)\s*)?0L?$/) {
+	$low = "0";
+	$high = "0";
+    } else {
+	$low = "($value) & 0xffff";
+	$high = "($value) << 16";
+    }
+
+    return ($low, $high);
+}
+
+sub fixup_function_call_2_forward_wm_call {
+    my $name = shift;
+    (my $hwnd, my $msg, my $wparam, my $lparam) = @{(shift)};
+
+    if($msg =~ /^(?:WM_BEGINDRAG|WM_ENTERMENULOOP|WM_EXITMENULOOP|WM_HELP|
+		  WM_ISACTIVEICON|WM_LBTRACKPOINT|WM_NEXTMENU)$/x) 
+    {
+	return undef;
+    }
+
+    my $suffix;
+    $name =~ /([AW])?$/;
+    if(defined($1)) {
+	$suffix = $1;
+    } else {
+	$suffix = "";
+    }
+
+    $wparam =~ s/^\(WPARAM\)//;
+    $lparam =~ s/^\(LPARAM\)//;
+
+    my @arguments;
+    if(0) {
+	# Nothing
+    } elsif($msg =~ /^WM_COMMAND$/) {
+	(my $id, my $code_notify) = _parse_makelong($wparam);
+	my $hwndctl = $lparam;
+	@arguments = ($id, $hwndctl, $code_notify);
+    } elsif($msg =~ /^WM_(?:COPY|CUT|PASTE)$/) {
+	@arguments = ();
+    } elsif($msg =~ /^WM_(?:CHARTO|VKEYTO)ITEM$/) {
+	(my $key, my $caret) = _parse_makelong($wparam);
+	my $hwndctl = $lparam;
+	@arguments = ($key, $hwndctl, $caret);
+    } elsif($msg =~ /^WM_(?:COMPARE|DELETE|DRAW|MEASURE)ITEM$/) {
+	@arguments = ($lparam);
+    } elsif($msg =~ s/^WM_GETTEXT$/$&$suffix/) {
+	@arguments = ($wparam, $lparam);
+    } elsif($msg =~ /^WM_INITMENU$/) {
+	my $hmenu = $wparam;
+	@arguments =  ($hmenu);
+    } elsif($msg =~ /^WM_INITMENUPOPUP$/) {
+	my $hmenu = $wparam;
+	(my $item, my $system_menu) = _parse_makelong($lparam);
+	@arguments =  ($hmenu, $item, $system_menu);
+    } elsif($msg =~ /^WM_MENUCHAR$/) {
+	(my $ch, my $flags) = _parse_makelong($wparam);
+	my $hmenu = $lparam;
+	@arguments = ($ch, $flags, $hmenu);
+    } elsif($msg =~ /^WM_MENUSELECT$/) {
+	(my $item, my $flags) = _parse_makelong($wparam);
+	my $hmenu = $lparam;
+	my $hmenu_popup = "NULL"; # FIXME: Is this really correct?
+	@arguments = ($hmenu, $item, $hmenu_popup, $flags);
+    } elsif($msg =~ s/^WM_(NC)?LBUTTONDBLCLK$/WM_$1LBUTTONDOWN/) {
+	my $double_click = "TRUE";
+	my $key_flags = $wparam;
+	(my $x, my $y) = _parse_makelong($lparam);
+	@arguments = ($double_click, $x, $y, $key_flags);
+    } elsif($msg =~ /^WM_(NC)?LBUTTONDOWN$/) {
+	my $double_click = "FALSE";
+	my $key_flags = $wparam;
+	(my $x, my $y) = _parse_makelong($lparam);
+	@arguments = ($double_click, $x, $y, $key_flags);
+    } elsif($msg =~ /^WM_LBUTTONUP$/) {
+	my $key_flags = $wparam;
+	(my $x, my $y) = _parse_makelong($lparam);
+	@arguments = ($x, $y, $key_flags);
+    } elsif($msg =~ /^WM_SETCURSOR$/) {
+	my $hwnd_cursor = $wparam;
+	(my $code_hit_test, my $msg2) = _parse_makelong($lparam);
+	@arguments = ($hwnd_cursor, $code_hit_test, $msg2);
+    } elsif($msg =~ s/^WM_SETTEXT$/$&$suffix/) {
+	my $text = $lparam;
+	@arguments = ($text);
+    } elsif($msg =~ /^WM_(?:SYS)?KEYDOWN$/) {
+	my $vk = $wparam;
+	(my $repeat, my $flags) = _parse_makelong($lparam);
+	@arguments = ($vk, $repeat, $flags);
+    } else {
+	@arguments = ($wparam, $lparam);
+    }
+    unshift @arguments, $hwnd;
+
+    return "FORWARD_" . $msg . "(" . join(", ", @arguments) . ", $name)";
+}
+
+sub fixup_statements {
+    my $function = shift;
+    my $editor = shift;
+
+    my $linkage = $function->linkage;
+    my $internal_name = $function->internal_name;
+    my $statements_line = $function->statements_line;
+    my $statements = $function->statements;
+    
+    if(($linkage eq "extern" && !defined($statements)) ||
+       ($linkage eq "" && !defined($statements)))
+    {
+	return;
+    }
+    
+    if($options->statements_windowsx && defined($statements)) {
+	my $found_function_call = sub {
+	    my $begin_line = shift;
+	    my $begin_column = shift;
+	    my $end_line = shift;
+	    my $end_column = shift;
+	    my $name = shift;
+	    my $arguments = shift;
+	    
+	    foreach my $argument (@$arguments) {
+		$argument =~ s/^\s*(.*?)\s*$/$1/;
+	    }
+
+	    if($options->statements_windowsx &&
+	       $name =~ /^(?:DefWindowProc|SendMessage)[AW]$/ &&
+	       $$arguments[1] =~ /^WM_\w+$/) 
+	    {
+		fixup_replace(\&fixup_function_call_2_forward_wm_call, $editor,
+			      $begin_line, $begin_column, $end_line, $end_column,
+			      $name, $arguments);
+	    } elsif(0) {
+		$output->write("$begin_line.$begin_column-$end_line.$end_column: " .
+			       "$name(" . join(", ", @$arguments) . ")\n");
+	    }
+	};
+	my $line = $statements_line;
+	my $column = 1;
+	
+	if(!&c_parser::parse_c_statements(\$statements, \$line, \$column, $found_function_call)) {
+	    $output->write("error: can't parse statements\n");
+	}
+    }
+}
+
+sub fixup_replace {
+    my $function = shift;
+    my $editor = shift;
+    my $begin_line = shift;
+    my $begin_column = shift;
+    my $end_line = shift;
+    my $end_column = shift;
+
+    my $replace = &$function(@_);
+
+    if(defined($replace)) {
+	$editor->replace($begin_line, $begin_column, $end_line, $end_column, $replace);
+    }
+}
+
+1;
diff --git a/tools/winapi_check/win32/shell32.api b/tools/winapi_check/win32/shell32.api
index d4afdf2..20ce347 100644
--- a/tools/winapi_check/win32/shell32.api
+++ b/tools/winapi_check/win32/shell32.api
@@ -6,7 +6,6 @@
 HANDLE
 HBITMAP
 HDROP
-HGLOBAL
 HMENU
 HICON
 HINSTANCE
diff --git a/tools/winapi_check/win32/wineps.api b/tools/winapi_check/win32/wineps.api
index 89b4309..6ab1056 100644
--- a/tools/winapi_check/win32/wineps.api
+++ b/tools/winapi_check/win32/wineps.api
@@ -20,19 +20,17 @@
 DOCINFOA *
 DWORD *
 INT *
+LPCVOID
 LPDEVMODEA
 LPINT
 LPLOGFONTW
 LPSIZE
+LPVOID
 POINT *
 RECT *
 TEXTMETRICW *
 void *
 
-%ptr # --forbidden
-
-SEGPTR
-
 %str 
 
 LPCSTR
diff --git a/tools/winapi_check/win32/x11drv.api b/tools/winapi_check/win32/x11drv.api
index 2dfd72c..77363b9 100644
--- a/tools/winapi_check/win32/x11drv.api
+++ b/tools/winapi_check/win32/x11drv.api
@@ -56,10 +56,6 @@
 WND *
 void *
 
-%ptr # --forbidden
-
-SEGPTR
-
 %str
 
 LPCSTR
diff --git a/tools/winapi_check/winapi_parser.pm b/tools/winapi_check/winapi_parser.pm
index 1e6e4af..3ade82d 100644
--- a/tools/winapi_check/winapi_parser.pm
+++ b/tools/winapi_check/winapi_parser.pm
@@ -30,6 +30,7 @@
 	my $argument_types;
 	my $argument_names;
 	my $argument_documentations;
+	my $statements_line;
 	my $statements;
 	
 	$function_begin = sub {
@@ -64,6 +65,7 @@
 	};
 
 	$function_end = sub {
+	    $statements_line = shift;
 	    $statements = shift;
 
 	    my $function = &$function_create_callback();
@@ -90,6 +92,7 @@
 	    if(defined($argument_documentations)) {
 		$function->argument_documentations([@$argument_documentations]);
 	    }
+	    $function->statements_line($statements_line);
 	    $function->statements($statements);
 	    
 	    &$function_found_callback($function);
@@ -127,6 +130,7 @@
     my %regs_entrypoints;
     my @comment_lines = ();
     my @comments = ();
+    my $statements_line;
     my $statements;
     my $level = 0;
     my $extern_c = 0;
@@ -163,9 +167,15 @@
 	}
       
 	# remove C comments
-	if(s/^(.*?)(\/\*.*?\*\/)(.*)$/$1 $3/s) { 
+	if(/^(.*?)(\/\*(.*?)\*\/)(.*)$/s) { 
+	    my @lines = split(/\n/, $2);
 	    push @comment_lines, $.; 
-	    push @comments, $2; 
+	    push @comments, $2;
+	    if($#lines <= 0) {
+		$_ = "$1 $4";
+	    } else {
+		$_ = $1 . ("\n" x $#lines) . $4;
+	    }
 	    $again = 1; 
 	    next;
 	}
@@ -175,23 +185,25 @@
 	}
 
 	# remove C++ comments
-	while(s/^(.*?)\/\/.*?$/$1\n/s) { $again = 1 }
+	while(s/^(.*?)\/\/.*?$/$1/s) { $again = 1 }
 	if($again) { next; }
 
-	# remove empty rows
-	if(/^\s*$/) { next; }
-
 	# remove preprocessor directives
-	if(s/^\s*\#/\#/m) {
-	    if(/^\\#.*?\\$/m) {
+	if(s/^\s*\#/\#/s) {
+	    if(/^\#.*?\\$/s) {
 		$lookahead = 1;
 		next;
-	    } elsif(s/^\#\s*(.*?)(\s+(.*?))?\s*$//m) {
+	    } elsif(s/^\#\s*(\w+)((?:\s+(.*?))?\s*)$//s) {
+		my @lines = split(/\n/, $2);
+		if($#lines > 0) {
+		    $_ = "\n" x $#lines;
+		}
 		if(defined($3)) {
 		    &$preprocessor_found_callback($1, $3);
 		} else {
 		    &$preprocessor_found_callback($1, "");
 		}
+		$again = 1;
 		next;
 	    }
 	}
@@ -282,6 +294,7 @@
 		$line .= "{";
 		print "+1: \{$_\n" if $options->debug >= 2;
 		$level++;
+		$statements .= $line;
 	    } elsif(s/^\}//) {
 		$_ = $'; $again = 1;
 		$line .= "}" if $level > 1;
@@ -291,15 +304,14 @@
 		    $extern_c = 0;
 		    $level = 0;
 		}
-	    }
-
-	    if($line !~ /^\s*$/) {
+		$statements .= $line;
+	    } else {
 		$statements .= "$line\n";
 	    }
 
 	    if($level == 0) {
 		if($in_function) {
-		    &$function_end($statements);
+		    &$function_end($statements_line, $statements);
 		    $statements = undef;
 		} elsif($in_type) {
 		    if(/^\s*(?:WINE_PACKED\s+)?((?:\*\s*)?\w+\s*(?:\s*,\s*(?:\*+\s*)?\w+)*\s*);/s) {
@@ -404,8 +416,9 @@
 			     $function_line, $linkage, $return_type, $calling_convention, $name,
 			     \@argument_types,\@argument_names,\@argument_documentations);
 	    if($level == 0) {
-		&$function_end(undef);
+		&$function_end(undef, undef);
 	    }
+	    $statements_line = $.;
 	    $statements = "";
 	} elsif(/__ASM_GLOBAL_FUNC\(\s*(.*?)\s*,/s) {
 	    my @lines = split(/\n/, $&);
@@ -415,7 +428,7 @@
 
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line, "", "void", "__asm", $1);
-	    &$function_end("");
+	    &$function_end($., "");
 	} elsif(/WAVEIN_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
 	    my @lines = split(/\n/, $&);
 	    my $function_line = $. - scalar(@lines) + 1;
@@ -425,10 +438,10 @@
 	    my @arguments32 = ("HWAVEIN");
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line,  "", "UINT16", "WINAPI", "waveIn" . $1 . "16", \@arguments16);
-	    &$function_end("");
+	    &$function_end($., "");
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line, "", "UINT", "WINAPI", "waveIn" . $1, \@arguments32);
-	    &$function_end("");
+	    &$function_end($., "");
 	} elsif(/WAVEOUT_SHORTCUT_0\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
 	    my @lines = split(/\n/, $&);
 	    my $function_line = $. - scalar(@lines) + 1;
@@ -439,10 +452,10 @@
 	    my @arguments32 = ("HWAVEOUT");
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line, "", "UINT16", "WINAPI", "waveOut" . $1 . "16", \@arguments16);
-	    &$function_end("");
+	    &$function_end($., "");
 	    &$function_begin($documentation_line, $documentation,
 			     $function_line, "", "UINT", "WINAPI", "waveOut" . $1, \@arguments32);	    
-	    &$function_end("");
+	    &$function_end($., "");
 	} elsif(/WAVEOUT_SHORTCUT_(1|2)\s*\(\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\)/s) {
 	    my @lines = split(/\n/, $&);
 	    my $function_line = $. - scalar(@lines) + 1;
@@ -454,19 +467,19 @@
 		my @arguments32 = ("HWAVEOUT", $4);
 		&$function_begin($documentation_line, $documentation,
 				 $function_line, "", "UINT16", "WINAPI", "waveOut" . $2 . "16", \@arguments16);
-		&$function_end("");
+		&$function_end($., "");
 		&$function_begin($documentation_line, $documentation,
 				 $function_line, "", "UINT", "WINAPI", "waveOut" . $2, \@arguments32);
-		&$function_end("");
+		&$function_end($., "");
 	    } elsif($1 eq 2) {
 		my @arguments16 = ("UINT16", $4);
 		my @arguments32 = ("UINT", $4);
 		&$function_begin($documentation_line, $documentation,
 				 $function_line, "", "UINT16", "WINAPI", "waveOut". $2 . "16", \@arguments16);
-		&$function_end("");
+		&$function_end($., "");
 		&$function_begin($documentation_line, $documentation, 
 				 $function_line, "", "UINT", "WINAPI", "waveOut" . $2, \@arguments32);
-		&$function_end("");
+		&$function_end($., "");
 	    }
         } elsif(/DEFINE_REGS_ENTRYPOINT_\d+\(\s*(\S*)\s*,\s*([^\s,\)]*).*?\)/s) {
 	    $_ = $'; $again = 1;