#!/usr/bin/perl # Documentation Checker # by trojal (modified by lighta) use strict; use File::Basename; use Getopt::Long; my $sHelp = 0; my $sAtcf = "../doc/atcommands.txt"; my $sSctf = "../doc/script_commands.txt"; my $sLeftOverChk = 0; my $sCmd = "chk"; my $sValidCmd = "ls|chk"; my $sTarget = "All"; my $sValidTarget = "All|Script|Atc"; my $sInc_atcf = "../doc/atcommands2.txt"; my $sInc_scrtf = "../doc/script_commands2.txt"; my($filename, $dir, $suffix) = fileparse($0); chdir $dir; #put ourself like was called in tool folder GetArgs(); Main($sCmd,$sTarget); sub GetArgs { GetOptions( 'cmd=s' => \$sCmd, # which command to run 'atcf=s' => \$sAtcf, #atcommand doc file 'scriptf=s' => \$sSctf, #script doc file 'inc_atcf=s' => \$sInc_atcf, #include script doc file (for customs doc) 'inc_scrtf=s' => \$sInc_scrtf, #include script doc file (for customs doc) 'target=s' => \$sTarget, #Target (wich files to run-cmd into) 'leftover=i' => \$sLeftOverChk, #should we chk if all doc are linked to a src ? 'help!' => \$sHelp, ) or $sHelp=1; #display help if invalid option if( $sHelp ) { print "Incorrect option specified, available options are:\n" ."\t --atcf filename => file (specify atcommand doc to use)\n" ."\t --inc_atcf filename => include file (specify atcommand doc to use)\n" ."\t --scriptf filename => file (specify script doc to use)\n" ."\t --inc_scrtf filename => include file (specify script doc to use)\n" ."\t --leftover=0|1 => should we run reverse chk for leftover in documentation ?\n" ."\t --target => target (specify wich check to run [$sValidTarget])\n" ."\t --cmd => cmd (specify wich command to run [(default)$sValidCmd])\n"; exit; } unless($sTarget =~ /$sValidTarget/i){ print "Incorrect target specified. Available targets:\n" ."\t --target => target (specify wich check to run [(default)$sValidTarget])\n"; exit; } unless($sCmd =~ /$sValidCmd/i){ print "Incorrect command specified. Available commands:\n" ."\t --cmd => cmd (specify wich command to run [(default)$sValidCmd])\n"; exit; } } sub Main { my ($sCmd,$sTarget) = @_; if($sTarget=~/both|all/i){ #both is keep as backard compatibility here cf check-doc.sh $sTarget = "script|atc"; } if($sTarget=~/script/i){ #find which script commands are missing from doc/script_commands.txt my $raSct_cmd = Script_GetCmd(); if($sCmd =~ /ls/i) { print "The list of script-commands found are = \n[ @$raSct_cmd ] \n\n"; } if($sCmd =~ /chk/i) { Script_Chk($raSct_cmd); } } if($sTarget=~/atc/i){ #find which atcommands are missing from doc/atcommands.txt my $raAct_cmd = Atc_GetCmd(); if($sCmd =~ /ls/i) { print "The list of atcommands found are = \n[ @$raAct_cmd ] \n\n"; } if($sCmd =~ /chk/i) { Atc_Chk($raAct_cmd); } } } sub Chk { my($raA,$raB) = @_; my @aMissing = (); foreach my $sA (@$raA){ my $sFound = 0; foreach my $sB (@$raB){ $sFound=1 if($sA eq $sB); } unless($sFound){ push(@aMissing,$sA); } } return \@aMissing; } sub Script_GetCmd { my @aSct_src = ("../src/map/script.cpp","../src/custom/script_def.inc"); my @aDef_sct = (); foreach my $sSct_srcf (@aSct_src){ unless(open FILE_SRC, "<$sSct_srcf") { print "Couldn't open file '$sSct_srcf'.\n"; next; } while(){ next if($_ =~ /^#/); #ignoe include, define or macro if($_ =~ /BUILDIN_DEF|BUILDIN_DEF2/){ $_ =~ s/\s+$//; #Remove trailing spaces. $_ =~ s/^\s+//; #Remove leading spaces. if($_ =~ /^BUILDIN_DEF2/){ my @line = split('"',$_); push(@aDef_sct,$line[1]); } elsif($_ =~ /^BUILDIN_DEF/){ my @line = split(',',$_); @line = split('\(',$line[0]); push(@aDef_sct,$line[1]); } } } close FILE_SRC; } return \@aDef_sct; } sub Script_Chk { my ($raDef_sct) = @_; my @aSct_docf = ($sSctf,$sInc_scrtf); my @aDoc_sct = (); my $raMiss_sct; foreach my $sSct_docf (@aSct_docf){ unless(open FILE_DOC, "$sSct_docf"){ print "Couldn't open file '$sSct_docf'.\n"; next; } while(){ next if($_ =~ /^\*\*|^\*\s|^\s+/); #discard **, * foo, foo next if(/^\s+/); if($_ =~ /^\*/){ my @line = split(' ',$_); @line = split('\(',$line[0]); @line = split('\<',$line[0]); $line[0] =~ s/\(|\{|\*|\r|\s|\;|\)|\"|\,//g; #todo please harmonize command definition for easier parse next if($line[0] eq "Name" || $line[0] eq "" || $line[0] eq "function" || $line[0] eq "if" || $line[0] eq "while" || $line[0] eq "do" || $line[0] eq "for" ); #exception list push(@aDoc_sct,$line[0]); } } close FILE_DOC; } $raMiss_sct = Chk($raDef_sct,\@aDoc_sct); #check missing documentation if(scalar(@$raMiss_sct)){ print "Missing script documentation for function :{\n"; foreach(@$raMiss_sct){ print "\t$_ \n"; } print "}\n\n"; } else { print "All script commands in src are documented, no issues found.\n"; } if($sLeftOverChk){ my $raLeftover_sct = Chk(\@aDoc_sct,$raDef_sct); #we just inverse the chk for leftover if(scalar(@$raLeftover_sct)){ print "These script commands were found in doc with no associated source:{\n"; foreach(@$raLeftover_sct){ print "\t$_ \n"; } print "}\n\n"; } else { print "All script commands in documentation match a source BUILDIN, no leftovers found.\n"; } } } sub Atc_GetCmd { my @aAct_src = ("../src/map/atcommand.cpp","../src/custom/atcommand_def.inc"); my @aDef_act = (); foreach my $sAct_srcf (@aAct_src){ unless(open FILE_SRC, "<$sAct_srcf"){ print "Couldn't open file '$sAct_srcf'.\n"; next; } while(){ next if($_ =~ /^#/); #ignore include, define or macro if($_ =~ /ACMD_DEF|ACMD_DEF2|ACMD_DEFR|ACMD_DEF2R/){ $_ =~ s/\s+$//; #Remove trailing spaces. $_ =~ s/^\s+//; #Remove leading spaces. if($_ =~ /^ACMD_DEF2|^ACMD_DEF2R/){ my @line = split('"',$_); push(@aDef_act,$line[1]); } elsif($_ =~ /^ACMD_DEF|^ACMD_DEFR/){ my @line = split(',',$_); @line = split('\(',$line[0]); $line[1] =~ s/\)//; #Remove closing brace push(@aDef_act,$line[1]); } } } close FILE_SRC; } return \@aDef_act; } sub Atc_Chk { my ($raDef_act) = @_; my @aAct_docf = ($sAtcf,$sInc_atcf); my @aDoc_act = (); my $raMiss_act; foreach my $sAct_docf (@aAct_docf){ unless(open FILE_DOC, "$sAct_docf"){ print "Couldn't open file '$sAct_docf'.\n"; next; } while(){ next if($_ =~ /^\*\*|^\*\s|^\s+/); #discard **, * foo, foo next if(/^\s+/); if($_ =~ /^\@/){ my @line = split(' ',$_); @line = split('\(',$line[0]); @line = split('\<',$line[0]); $line[0] =~ s/\(|\{|\@|\r|\s|\;|\)|\"|\,//g; #todo please harmonize command definition for easier parse push(@aDoc_act,$line[0]); } } close FILE_DOC; } $raMiss_act = Chk($raDef_act,\@aDoc_act); #check missing documentation if(scalar(@$raMiss_act)){ print "Missing atcommand documentation for function :{\n"; foreach(@$raMiss_act){ print "\t$_ \n"; } print "}\n\n"; } else { print "All atcommands in src are documented, no issues found.\n"; } if($sLeftOverChk){ my $raLeftover_sct = Chk(\@aDoc_act,$raDef_act); #we just inverse the chk for leftover if(scalar(@$raLeftover_sct)){ print "These atcommands were found in doc with no associated source: {\n"; foreach(@$raLeftover_sct){ print "\t$_ \n"; } print "}\n\n"; } else { print "All atcommands in documentation match a source ATCMD, no leftovers found.\n"; } } }