test1222.pl 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #!/usr/bin/env perl
  2. #***************************************************************************
  3. # _ _ ____ _
  4. # Project ___| | | | _ \| |
  5. # / __| | | | |_) | |
  6. # | (__| |_| | _ <| |___
  7. # \___|\___/|_| \_\_____|
  8. #
  9. # Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  10. #
  11. # This software is licensed as described in the file COPYING, which
  12. # you should have received as part of this distribution. The terms
  13. # are also available at https://curl.se/docs/copyright.html.
  14. #
  15. # You may opt to use, copy, modify, merge, publish, distribute and/or sell
  16. # copies of the Software, and permit persons to whom the Software is
  17. # furnished to do so, under the terms of the COPYING file.
  18. #
  19. # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  20. # KIND, either express or implied.
  21. #
  22. # SPDX-License-Identifier: curl
  23. #
  24. #
  25. ###########################################################################
  26. #
  27. # Check that the deprecated statuses of functions and enum values in header
  28. # files, manpages and symbols-in-versions are in sync.
  29. use strict;
  30. use warnings;
  31. use File::Basename;
  32. my $root=$ARGV[0] || ".";
  33. my $incdir = "$root/include/curl";
  34. my $docdir = "$root/docs";
  35. my $libdocdir = "$docdir/libcurl";
  36. my $errcode = 0;
  37. # Symbol-indexed hashes.
  38. # Values are:
  39. # X Not deprecated
  40. # ? Deprecated in unknown version
  41. # x.yy.z Deprecated in version x.yy.z
  42. my %syminver; # Symbols-in-versions deprecations.
  43. my %hdr; # Public header files deprecations.
  44. my %funcman; # Function manpages deprecations.
  45. my %optman; # Option manpages deprecations.
  46. # Scan header file for public function and enum values. Flag them with
  47. # the version they are deprecated in, if some.
  48. sub scan_header {
  49. my ($f)=@_;
  50. my $line = "";
  51. my $incomment = 0;
  52. my $inenum = 0;
  53. open(my $h, "<", "$f");
  54. while(<$h>) {
  55. s/^\s*(.*?)\s*$/$1/; # Trim.
  56. # Remove multi-line comment trail.
  57. if($incomment) {
  58. if($_ !~ /.*?\*\/\s*(.*)$/) {
  59. next;
  60. }
  61. $_ = $1;
  62. $incomment = 0;
  63. }
  64. if($line ne "") {
  65. # Unfold line.
  66. $_ = "$line $1";
  67. $line = "";
  68. }
  69. # Remove comments.
  70. while($_ =~ /^(.*?)\/\*.*?\*\/(.*)$/) {
  71. $_ = "$1 $2";
  72. }
  73. if($_ =~ /^(.*)\/\*/) {
  74. $_ = "$1 ";
  75. $incomment = 1;
  76. }
  77. s/^\s*(.*?)\s*$/$1/; # Trim again.
  78. # Ignore preprocessor directives and blank lines.
  79. if($_ =~ /^(?:#|$)/) {
  80. next;
  81. }
  82. # Handle lines that may be continued as if they were folded.
  83. if($_ !~ /[;,{}]$/) {
  84. # Folded line.
  85. $line = $_;
  86. next;
  87. }
  88. if($_ =~ /CURLOPTDEPRECATED\(/) {
  89. # Handle deprecated CURLOPT_* option.
  90. if($_ !~ /CURLOPTDEPRECATED\(\s*(\S+)\s*,(?:.*?,){2}\s*(.*?)\s*,.*"\)/) {
  91. # Folded line.
  92. $line = $_;
  93. next;
  94. }
  95. $hdr{$1} = $2;
  96. }
  97. elsif($_ =~ /CURLOPT\(/) {
  98. # Handle non-deprecated CURLOPT_* option.
  99. if($_ !~ /CURLOPT\(\s*(\S+)\s*(?:,.*?){2}\)/) {
  100. # Folded line.
  101. $line = $_;
  102. next;
  103. }
  104. $hdr{$1} = "X";
  105. }
  106. else {
  107. my $version = "X";
  108. # Get other kind of deprecation from this line.
  109. if($_ =~ /CURL_DEPRECATED\(/) {
  110. if($_ !~ /^(.*)CURL_DEPRECATED\(\s*(\S+?)\s*,.*?"\)(.*)$/) {
  111. # Folded line.
  112. $line = $_;
  113. next;
  114. }
  115. $version = $2;
  116. $_ = "$1 $3";
  117. }
  118. if($_ =~ /^CURL_EXTERN\s+.*\s+(\S+?)\s*\(/) {
  119. # Flag public function.
  120. $hdr{$1} = $version;
  121. }
  122. elsif($inenum && $_ =~ /(\w+)\s*[,=}]/) {
  123. # Flag enum value.
  124. $hdr{$1} = $version;
  125. }
  126. }
  127. # Remember if we are in an enum definition.
  128. $inenum |= ($_ =~ /\benum\b/);
  129. if($_ =~ /}/) {
  130. $inenum = 0;
  131. }
  132. }
  133. close $h;
  134. }
  135. # Scan function manpage for options.
  136. # Each option has to be declared as ".IP <option>" where <option> starts with
  137. # the prefix. Flag each option with its deprecation version, if some.
  138. sub scan_man_for_opts {
  139. my ($f, $prefix)=@_;
  140. my $opt = "";
  141. my $line = "";
  142. open(my $m, "<", "$f");
  143. while(<$m>) {
  144. if($_ =~ /^\./) {
  145. # roff directive found: end current option paragraph.
  146. my $o = $opt;
  147. $opt = "";
  148. if($_ =~ /^\.IP\s+((?:$prefix)_\w+)/) {
  149. # A new option has been found.
  150. $opt = $1;
  151. }
  152. $_ = $line; # Get full paragraph.
  153. $line = "";
  154. s/\\f.//g; # Remove font formatting.
  155. s/\s+/ /g; # One line with single space only.
  156. if($o) {
  157. $funcman{$o} = "X";
  158. # Check if paragraph is mentioning deprecation.
  159. while($_ =~ /(?:deprecated|obsoleted?)\b\s*(?:in\b|since\b)?\s*(?:version\b|curl\b|libcurl\b)?\s*(\d[0-9.]*\d)?\b\s*(.*)$/i) {
  160. $funcman{$o} = $1 || "?";
  161. $_ = $2;
  162. }
  163. }
  164. }
  165. else {
  166. # Text line: accumulate.
  167. $line .= $_;
  168. }
  169. }
  170. close $m;
  171. }
  172. # Scan manpage for deprecation in DESCRIPTION and/or AVAILABILITY sections.
  173. sub scan_man_page {
  174. my ($path, $sym, $table)=@_;
  175. my $version = "X";
  176. if(open(my $fh, "<", "$path")) {
  177. my $section = "";
  178. my $line = "";
  179. while(<$fh>) {
  180. if($_ =~ /\.so\s+man3\/(.*\.3\b)/) {
  181. # Handle manpage inclusion.
  182. scan_man_page(dirname($path) . "/$1", $sym, $table);
  183. $version = exists($$table{$sym})? $$table{$sym}: $version;
  184. }
  185. elsif($_ =~ /^\./) {
  186. # Line is a roff directive.
  187. if($_ =~ /^\.SH\b\s*(\w*)/) {
  188. # Section starts. End previous one.
  189. my $sh = $section;
  190. $section = $1;
  191. $_ = $line; # Previous section text.
  192. $line = "";
  193. s/\\f.//g;
  194. s/\s+/ /g;
  195. s/\\f.//g; # Remove font formatting.
  196. s/\s+/ /g; # One line with single space only.
  197. if($sh =~ /DESCRIPTION|DEPRECATED/) {
  198. while($_ =~ /(?:deprecated|obsoleted?)\b\s*(?:in\b|since\b)?\s*(?:version\b|curl\b|libcurl\b)?\s*(\d[0-9.]*\d)?\b\s*(.*)$/i) {
  199. # Flag deprecation status.
  200. if($version ne "X" && $version ne "?") {
  201. if($1 && $1 ne $version) {
  202. print "error: $sym manpage lists unmatching deprecation versions $version and $1\n";
  203. $errcode++;
  204. }
  205. }
  206. else {
  207. $version = $1 || "?";
  208. }
  209. $_ = $2;
  210. }
  211. }
  212. }
  213. }
  214. else {
  215. # Text line: accumulate.
  216. $line .= $_;
  217. }
  218. }
  219. close $fh;
  220. $$table{$sym} = $version;
  221. }
  222. }
  223. # Read symbols-in-versions.
  224. open(my $fh, "<", "$libdocdir/symbols-in-versions") ||
  225. die "$libdocdir/symbols-in-versions";
  226. while(<$fh>) {
  227. if($_ =~ /^((?:CURL|LIBCURL)\S+)\s+\S+\s*(\S*)\s*(\S*)$/) {
  228. if($3 eq "") {
  229. $syminver{$1} = "X";
  230. if($2 ne "" && $2 ne ".") {
  231. $syminver{$1} = $2;
  232. }
  233. }
  234. }
  235. }
  236. close($fh);
  237. # Get header file names,
  238. opendir(my $dh, $incdir) || die "Can't opendir $incdir";
  239. my @hfiles = grep { /\.h$/ } readdir($dh);
  240. closedir $dh;
  241. # Get functions and enum symbols from header files.
  242. for(@hfiles) {
  243. scan_header("$incdir/$_");
  244. }
  245. # Get function statuses from manpages.
  246. foreach my $sym (keys %hdr) {
  247. if($sym =~/^(?:curl|curlx)_\w/) {
  248. scan_man_page("$libdocdir/$sym.3", $sym, \%funcman);
  249. }
  250. }
  251. # Get options from function manpages.
  252. scan_man_for_opts("$libdocdir/curl_easy_setopt.3", "CURLOPT");
  253. scan_man_for_opts("$libdocdir/curl_easy_getinfo.3", "CURLINFO");
  254. # Get deprecation status from option manpages.
  255. foreach my $sym (keys %syminver) {
  256. if($sym =~ /^(?:CURLOPT|CURLINFO)_\w+$/) {
  257. scan_man_page("$libdocdir/opts/$sym.3", $sym, \%optman);
  258. }
  259. }
  260. # Print results.
  261. my %keys = (%syminver, %funcman, %optman, %hdr);
  262. my $leader = <<HEADER
  263. Legend:
  264. <empty> Not listed
  265. X Not deprecated
  266. ? Deprecated in unknown version
  267. x.yy.z Deprecated in version x.yy.z
  268. Symbol symbols-in func man opt man .h
  269. -versions
  270. HEADER
  271. ;
  272. foreach my $sym (sort {$a cmp $b} keys %keys) {
  273. if($sym =~ /^(?:CURLOPT|CURLINFO|curl|curlx)_\w/) {
  274. my $s = exists($syminver{$sym})? $syminver{$sym}: " ";
  275. my $f = exists($funcman{$sym})? $funcman{$sym}: " ";
  276. my $o = exists($optman{$sym})? $optman{$sym}: " ";
  277. my $h = exists($hdr{$sym})? $hdr{$sym}: " ";
  278. my $r = " ";
  279. # There are deprecated symbols in symbols-in-versions that are aliases
  280. # and thus not listed anywhere else. Ignore them.
  281. "$f$o$h" =~ /[X ]{3}/ && next;
  282. # Check for inconsistencies between deprecations from the different sources.
  283. foreach my $k ($s, $f, $o, $h) {
  284. $r = $r eq " "? $k: $r;
  285. if($k ne " " && $r ne $k) {
  286. if($r eq "?") {
  287. $r = $k ne "X"? $k: "!";
  288. }
  289. elsif($r eq "X" || $k ne "?") {
  290. $r = "!";
  291. }
  292. }
  293. }
  294. if($r eq "!") {
  295. print $leader;
  296. $leader = "";
  297. printf("%-38s %-11s %-9s %-9s %s\n", $sym, $s, $f, $o, $h);
  298. $errcode++;
  299. }
  300. }
  301. }
  302. exit $errcode;