diff --git a/runoff b/runoff
index 1d0fbb5c6104a887ce6270be35b477b7fb3f10d2..5a1b55668e0f0ad16a33fd874b1b56842b1ccf40 100755
--- a/runoff
+++ b/runoff
@@ -16,13 +16,94 @@ files=`grep -v '^#' runoff.list | awk '{print $1}'`
 n=99
 for i in $files
 do
-	awk -v 'n='$n '
-		BEGIN{n=int((n+49)/50)*50-1; nb=0; nr=0}
-		NF==0 { nb++; next } 
-		{for(i=0; i<nb; i++) printf("%04d\n", n+ ++nr); nb=0; printf("%04d %s\n", n+ ++nr, $0)}
-		END{for(nr++; nr%50 != 1; nr++) printf("%04d\n", n+nr);}
-		' $i >fmt/$i
-	n=`tail -1 fmt/$i | awk '{print $1}'`
+	perl -e '$n='$n';' -e ' 
+		$n = int(($n+49)/50)*50 - 1;
+
+		@lines = <>;
+		foreach (@lines) {
+			chomp;
+			s/\s+$//;
+			if(length() >= 75){
+				print "$ARGV[0]:$.: line too long";
+			}
+		}
+		@outlines = ();
+		$nextout = 0;
+		for($i=0; $i<@lines; ){
+			# Skip leading blank lines.
+			$i++ while $i<@lines && $lines[$i] =~ /^$/;
+			last if $i>=@lines;
+
+			# If the rest of the file fits, use the whole thing.
+			if(@lines <= $i+50){
+				$breakbefore = @lines;
+			}else{
+				# Find a good next page break;
+				# Hope for end of function.
+				# but settle for a blank line (but not first blank line
+				# in function, which comes after variable declarations).
+				$breakbefore = $i;
+				$lastblank = $i;
+				$sawbrace = 0;
+				$breaksize = 15;  # 15 lines to get to function
+				for($j=$i; $j<$i+50 && $j < @lines; $j++){
+					if($lines[$j] =~ /PAGEBREAK:\s*([0-9]+)/){
+						$breaksize = int($2);
+						$breakbefore = $j;
+						$lines[$j] = "";
+					}
+					if($lines[$j] =~ /^}$/){
+						$breakbefore = $j+1;
+					}
+					if($lines[$j] =~ /^{$/){
+						$sawbrace = 1;
+					}
+					if($lines[$j] =~ /^$/){
+						if($sawbrace){
+							$sawbrace = 0;
+						}else{
+							$lastblank = $j;
+						}
+					}
+				}
+				if($j<@lines && $lines[$j] =~ /^$/){
+					$lastblank = $j;
+				}
+				
+				# If we are not putting enough on a page, try a blank line.
+				if($breakbefore - $i < 50 - $breaksize && $lastblank > $breakbefore && $lastblank >= $i+50 - 5){
+					$breakbefore = $lastblank;
+					$breaksize = 5;  # only 5 lines to get to blank line
+				}
+
+				# If we are not putting enough on a page, force a full page.
+				if($breakbefore - $i < 50 - $breaksize && $breakbefore != @lines){
+					$breakbefore = $i + 50;
+					$breakbefore = @lines if @lines < $breakbefore;
+				}
+
+				if($breakbefore < $i+2){
+					$breakbefore = $i+2;
+				}
+			}
+
+			# Emit the page.
+			$i50 = $i + 50;
+			for(; $i<$breakbefore; $i++){
+				printf "%04d %s\n", ++$n, $lines[$i];
+			}
+
+			# Finish page
+			for($j=$i; $j<$i50; $j++){
+				printf "%04d \n", ++$n;
+			}
+		}
+	' $i >fmt/$i
+
+	nn=`tail -1 fmt/$i | sed 's/ .*//; s/^0*//'`
+	if [ "x$nn" != x ]; then
+		n=$nn
+	fi
 done
 
 # create table of contents
@@ -117,7 +198,7 @@ awk '
 # format the whole thing
 (
 	pr -l60 -e8 README
-	pr -l60 -e8 -2 toc
+	pr -l60 -h "table of contents" -e8 -2 toc
 	pr -l60 -h "definitions" -2 t.defs | pad
 	pr -l60 -h "cross-references" -2 refs | pad 
 	for i in $files