#!/usr/local/bin/perl # # checktables.pl - Verify your HTML code so your tables will work and look # good in Netscape (which does not obey the HTML specification). # # Written by Bjorn Stenberg (bjorn.stenberg@sth.frontec.se) 980725 # $argc=@ARGV; boo: while ( $x < $argc ) { if ( $ARGV[$x] eq "-h" ) { &usage; } elsif ( $ARGV[$x] eq "-v" ) { $verbose = 1; } else { $filename = $ARGV[$x]; last boo; } $x++; } if ( $filename eq "" ) { &usage; exit; } sub usage { print "usage: checktables.pl [-v] [-h] htmlfile\n"; print "\t-v produces a \"graph\" of the table structure\n"; print "\t-h produces this help text\n"; exit; } sub add { $a = "$a "; } sub del { $a = substr( $a, 0,length($a)-2); } %ok=("table",1,"tr",1,"td",1,"/table",1,"/tr",1,"/td",1); # # Allowed sequences of tags (on the same level) # # table, /table, tr, /tr, td, /td # table 0 1 0 0 1 0 # /table 1 0 0 1 0 0 # tr 1 0 0 1 0 0 # /tr 0 0 1 0 0 1 # td 0 0 1 0 0 1 # /td 0 0 0 1 1 0 %allow=("table","/table,td", "/table", "table,/tr", "tr", "table,/tr", "/tr", "tr,/td", "td", "tr,/td", "/td", "/tr,td" ); $help{"table","table"} ="/table"; $help{"tr","table"} ="td"; $help{"/tr","table"} ="/table"; $help{"/td","table"} ="td"; $help{"/table","/table"}="table"; $help{"tr","/table"} ="/tr"; $help{"td","/table"} ="table"; $help{"/td","/table"} ="/tr"; $help{"/table","tr"} ="table"; $help{"tr","tr"} ="/tr"; $help{"td","tr"}="/td"; $help{"/td","tr"} ="/tr"; $help{"table","/tr"} = "tr"; $help{"/table","/tr"} = "table"; $help{"/tr","/tr"} = "tr"; $help{"td","/tr"} = "/td"; $help{"table","td"} = "tr"; $help{"/table","td"} = "table"; # -> table+td -> table+tr+td $help{"/tr","td"} = "tr"; $help{"td","td"} = "/td"; $help{"table","/td"} = "td"; # -> table+td -> table+tr+td $help{"/table","/td"} = "table"; # -> table+/td -> table+td+/td -> t+tr+td $help{"tr","/td"} = "td"; $help{"/td","/td"} = "td"; open(FILE, "<$filename"); if ($verbose){ print "line tag level\n"; } loop: while() { $in = $_; $line++; # print "\rLine $line\n"; hej: # print "In: $in"; if ( ($pos = index( $in, "<" )) >=0 ) { $tag = substr($in,$pos+1); if ( "/" eq substr( $tag, 0, 1 ) ) { $dir = -1; } else { $dir = 1; } if( $tag =~ /([^> ]*)/ ) { $tag = $1; # print "Tag: $tag\n"; } } else { $type = ""; next loop; } # print "$line: In1: $in\n"; # skip a bit, brother $in = substr( $in, $pos+length($tag)+2 ); # print "$line: In2: $in\n"; # skip all but desired tags if ( $ok{$tag} != 1 ) { goto hej; } $tags++; # print "$line: Tag <$tag>, level $lvl\n"; # is this tag allowed? if ( $lvl >0 ) { @options=split(",",$allow{$tag}); for ( @options ) { # print "$line: $tag allowed after $_\. lasttag is $lasttag[$lvl]\n"; if ( ( "" ne $lasttag[$lvl] ) && ( $_ eq $lasttag[$lvl] ) ) { goto ok; } } if ($verbose){ printf("%3d !! <%s> %d !!\n",$line,$tag,$lvl); } print "Bad sequence on line $line (level $lvl): A <$tag> after the <$lasttag[$lvl]> on line $lastline[$lvl]\n"; $l1 = ($lastline[$lvl+1]+1); if ( $l1 < $lastline[$lvl] ) { $l1 = $lastline[$lvl] } $l2 = ($line-1); if ( $l2 < $l1 ) { $l2 = $l1 } print "It looks like you've missed a <$help{$lasttag[$lvl],$tag}> "; if ( $l1 != $l2 ) { printf "somewhere between line %d and %d.\n", $l1, $l2; } else { print "on line $l1.\n"; } close(FILE); exit; } ok: if ( $dir > 0 ) { $lvl += $dir; $lasttag[$lvl] = $tag; $lastline[$lvl] = $line; if ($verbose){ printf("%3d $a<%s> %d \n",$line,$tag,$lvl); } &add; } else { &del; if ($verbose){ printf("%3d $a<%s> %d \n",$line,$tag,$lvl); } $lasttag[$lvl] = ($tag,$line); $lastline[$lvl] = $line; $lvl += $dir; } goto hej; } close(FILE); if (!$tags) { print "There are no tables in this page.\n"; } else { print "All tables appear to be correct.\n"; }