commandref_join.pl 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #!/usr/bin/perl
  2. # Usage:
  3. # if called with FHEM/XX.pm, than only this file will be checked
  4. # MAXWI
  5. # With pre: 1320, without 1020 (content only)
  6. # pre { white-space: pre-wrap; } : 900
  7. use strict;
  8. use warnings;
  9. # $Id: commandref_join.pl 16425 2018-03-17 15:27:04Z rudolfkoenig $
  10. my $noWarnings = grep $_ eq '-noWarnings', @ARGV;
  11. my ($verify) = grep $_ =~ /\.pm$/ , @ARGV;
  12. use constant TAGS => qw{ul li code b i u table tr td div h4 h3};
  13. sub generateModuleCommandref($$;$$);
  14. my %mods;
  15. my %modIdx;
  16. my @modDir = ("FHEM");
  17. my @lang = ("EN", "DE");
  18. if(!$verify) {
  19. foreach my $modDir (@modDir) {
  20. opendir(DH, $modDir) || die "Cant open $modDir: $!\n";
  21. while(my $l = readdir DH) {
  22. next if($l !~ m/^\d\d_.*\.pm$/);
  23. my $of = $l;
  24. $l =~ s/.pm$//;
  25. $l =~ s/^[0-9][0-9]_//;
  26. $mods{$l} = "$modDir/$of";
  27. $modIdx{$l} = "device";
  28. my $modFh;
  29. open($modFh, "$modDir/$of") || die("Cant open $modDir/$l");
  30. while(my $cl = <$modFh>) {
  31. if($cl =~ m/^=item\s+(helper|command|device)/) {
  32. $modIdx{$l} = $1;
  33. last;
  34. }
  35. }
  36. close($modFh);
  37. }
  38. }
  39. if(-f "configDB.pm") {
  40. $mods{configDB} = "configDB.pm";
  41. $modIdx{configDB} = "helper";
  42. }
  43. } else { # check for syntax only
  44. my $modname = $verify;
  45. $modname =~ s/^.*[\/\\](?:\d\d_)?(.+).pm$/$1/;
  46. $mods{$modname} = $verify;
  47. foreach my $lang (@lang) {
  48. generateModuleCommandref($modname, $lang);
  49. }
  50. exit;
  51. }
  52. sub
  53. printList($)
  54. {
  55. for my $i (sort { "\L$a" cmp "\L$b" } keys %modIdx) {
  56. print OUT " <a href=\"#$i\">$i</a> &nbsp;\n"
  57. if($modIdx{$i} eq $_[0]);
  58. }
  59. while(my $l = <IN>) {
  60. next if($l =~ m/href=/);
  61. print OUT $l;
  62. last;
  63. }
  64. }
  65. my $var;
  66. sub
  67. chkAndGenLangLinks($$$)
  68. {
  69. my ($l, $lang, $fh) = @_;
  70. $var = $1 if($l =~ m/<a name="(.*?)"(.*?)><\/a>/);
  71. if($fh && $l =~ m/(.*?)<\/h3>/ && $var) {
  72. print $fh "<div class='langLinks'>[".join(" ", map {
  73. $_ eq $lang ? $_ :
  74. "<a href='commandref".($_ eq "EN" ? "":"_$_").".html#$var'>$_</a>"
  75. } @lang) . "]</div>\n";
  76. $var = undef;
  77. }
  78. }
  79. foreach my $lang (@lang) {
  80. my $suffix = ($lang eq "EN" ? "" : "_$lang");
  81. my $docIn = "docs/commandref_frame$suffix.html";
  82. my $docOut = "docs/commandref$suffix.html";
  83. open(IN, "$docIn") || die "Cant open $docIn: $!\n";
  84. open(OUT, ">$docOut") || die "Cant open $docOut: $!\n";
  85. if(!$suffix) { # First run: remember commands/helper module
  86. my $modType;
  87. while(my $l = <IN>) {
  88. $modType = "command" if($l =~ m/>FHEM commands</);
  89. $modType = "device" if($l =~ m/>Device modules</);
  90. $modType = "helper" if($l =~ m/>Helper modules</);
  91. $modIdx{$1} = $modType
  92. if($modType && $l =~ m/href="#(.*?)">/ && $1 ne "global");
  93. last if($l =~ m/<!-- header end -->/);
  94. }
  95. seek(IN,0,0);
  96. }
  97. # Second run: create the file
  98. while(my $l = <IN>) { # Header
  99. last if($l =~ m/name="perl"/);
  100. print OUT $l;
  101. chkAndGenLangLinks($l, $lang, \*OUT);
  102. printList($1) if($l =~ m/<!-- header:(.*) -->/);
  103. }
  104. # Copy the doc part from the module
  105. foreach my $mod (sort keys %mods) {
  106. generateModuleCommandref($mod,$lang, \*OUT);
  107. }
  108. # Copy the tail
  109. print OUT '<a name="perl"></a>',"\n";
  110. $var = "perl";
  111. while(my $l = <IN>) {
  112. print OUT $l;
  113. chkAndGenLangLinks($l, $lang, \*OUT);
  114. }
  115. close(OUT);
  116. }
  117. #############################
  118. # read a module file and check/print the commandref
  119. sub
  120. generateModuleCommandref($$;$$)
  121. {
  122. my ($mod, $lang, $fh, $jsFile) = @_;
  123. my $fPath = $mods{$mod} ? $mods{$mod} : $mod;
  124. my $tag;
  125. my $suffix = ($lang eq "EN" ? "" : "_$lang");
  126. my %tagcount= ();
  127. map { $tagcount{$_} = 0 } TAGS;
  128. my %llwct = (); # Last line with closed tag
  129. my $modFh;
  130. open($modFh, $fPath) || die("Cant open $fPath:$!\n");
  131. my $skip = 1;
  132. my $line = 0;
  133. my $docCount = 0;
  134. my $hasLink = 0;
  135. my $dosMode = 0;
  136. while(my $l = <$modFh>) {
  137. $line++;
  138. $dosMode = 1 if($l =~ m/^=begin html$suffix.*\r/);
  139. if($l =~ m/^=begin html$suffix$/) {
  140. $l = <$modFh>; # skip one line, to be able to repeat join+split
  141. print "*** $lang $mod: nonempty line after =begin html ignored\n"
  142. if($l =~ m/^...*$/);
  143. $skip = 0; $line++;
  144. } elsif($l =~ m/^=end html$suffix$/) {
  145. $skip = 1;
  146. print $fh "<p>" if($fh);
  147. } elsif(!$skip) {
  148. print $fh $l if($fh);
  149. chkAndGenLangLinks($l, $lang, $fh);
  150. $docCount++;
  151. $hasLink = ($l =~ m/<a name="$mod"/) if(!$hasLink);
  152. foreach $tag (TAGS) {
  153. $tagcount{$tag} +=()= ($l =~ /<$tag>/gi);
  154. $tagcount{$tag} -=()= ($l =~ /<\/$tag>/gi);
  155. if($tagcount{$tag} < 0) {
  156. print "*** $lang $fPath: negative tagcount for $tag, line $line\n"
  157. if(!$noWarnings);
  158. $tagcount{$tag} = 0;
  159. }
  160. $llwct{$tag} = $line if(!$tagcount{$tag});
  161. }
  162. if($l =~ m,INSERT_DOC_FROM: ([^ ]+)/([^ /]+) ,) {
  163. my ($dir, $re) = ($1, $2);
  164. if(opendir(DH, $dir)) {
  165. foreach my $file (grep { m/^$2$/ } readdir(DH)) {
  166. generateModuleCommandref("$dir/$file", $lang, $fh, 1);
  167. }
  168. closedir(DH);
  169. }
  170. }
  171. }
  172. }
  173. close($modFh);
  174. print "*** $lang $fPath: ignoring text due to DOS encoding\n"
  175. if($dosMode);
  176. # TODO: add doc to each $jsfile
  177. print "*** $lang $fPath: No document text found\n"
  178. if(!$jsFile && !$suffix && !$docCount && !$dosMode && $fPath !~ m,/99_,);
  179. if(!$jsFile && $suffix && !$docCount && !$dosMode) {
  180. if($lang eq "DE" && $fh) {
  181. print $fh <<EOF;
  182. <a name="$mod"></a>
  183. <h3>$mod</h3>
  184. <ul>
  185. Leider keine deutsche Dokumentation vorhanden. Die englische Version gibt es
  186. hier: <a href='commandref.html#$mod'>$mod</a><br/>
  187. </ul>
  188. EOF
  189. }
  190. }
  191. print "*** $lang $fPath: No a-tag with name=\"$mod\" \n"
  192. if(!$jsFile && !$suffix && $docCount && !$hasLink && !$noWarnings);
  193. foreach $tag (TAGS) {
  194. print("*** $lang $fPath: Unbalanced $tag ".
  195. "($tagcount{$tag}, last line ok: $llwct{$tag})\n")
  196. if($tagcount{$tag} && !$noWarnings);
  197. }
  198. }