]> Sergey Matveev's repositories - dotfiles.git/blob - bin/bin/docstringer.pl
1e3f1e14e045cfccc8d5cf34f73f405e35747288
[dotfiles.git] / bin / bin / docstringer.pl
1 #!/usr/bin/env perl
2 # Simple script for substitute placeholders in Texinfo files with
3 # docstring values found in source code.
4 # Copyright (C) 2020-2025 Sergey Matveev <stargrave@stargrave.org>
5 #
6 # If you C source code contains:
7 #
8 #     // TEXINFO: SomeKey
9 #     // ...
10 #     // last line of docstring
11 #     some C code
12 #
13 # Then under "SomeKey" you will have the whole docstring (starting from
14 # the line after "TEXINFO", till "last line"). You can include its
15 # contents (excluding comment characters) in your .texi files placing
16 #
17 #     @DOCSTRING SomeKey@
18
19 use strict;
20 use warnings;
21 use Carp q{croak};
22
23 my $verbose = 0;
24 if ($ARGV[0] eq q{-v}) {
25     $verbose = 1;
26     shift @ARGV;
27 }
28 my $outDir = $ARGV[0];
29 my @srcDirs = split /:/, $ARGV[1];
30 my @docDirs = split /:/, $ARGV[2];
31 my @exts = (defined $ENV{EXTS}) ? (split / /, $ENV{EXTS}) : qw{c h h.in};
32 my %docstrings;
33
34 foreach my $srcDir (@srcDirs) {
35     if ($verbose) {
36         print "src: $srcDir\n";
37     }
38     opendir my $dir, $srcDir or croak "can not open $srcDir";
39     foreach my $fn (readdir $dir) {
40         foreach (@exts) {
41             if ($fn =~ /[.]$_$/) {
42                 goto ExtIsGood;
43             }
44         }
45         next;
46     ExtIsGood:
47         open my $src, q{<:encoding(UTF-8)}, "$srcDir/$fn" or croak "can not open $srcDir/$fn";
48         my $curEntry;
49         while (<$src>) {
50             chomp;
51             if (not /^\/\//) {
52                 if (defined $curEntry) {
53                     undef $curEntry;
54                 }
55                 next;
56             }
57             s/^\/\/[ ]?//;
58             if (/^TEXINFO: (.*)$/) {
59                 $curEntry = $1;
60                 $docstrings{$curEntry} = q{};
61                 if ($verbose) {
62                     print "\t$fn: $curEntry\n";
63                 }
64                 next;
65             }
66             if (defined $curEntry) {
67                 $docstrings{$curEntry} .= "$_\n";
68             }
69         }
70         close $src or croak "$!";
71     }
72     closedir $dir;
73 }
74
75 foreach my $docDir (@docDirs) {
76     if ($verbose) {
77         print "doc: $docDir\n";
78     }
79     opendir my $dir, $docDir or croak "can not open $docDir";
80     if ($docDir !~ /[\/]$/) {
81         $docDir .= q{/};
82     }
83     if ($docDir eq q{./}) {
84         $docDir = q{};
85     }
86     foreach my $fn (readdir $dir) {
87         if ($fn !~ /[.]texi$/) {
88             next;
89         }
90         $fn = $docDir . $fn;
91         open my $src, q{<:encoding(UTF-8)}, $fn or croak "can not open $fn";
92         mkdir "$outDir/$docDir";
93         open my $dst, q{>:encoding(UTF-8)}, "$outDir/$fn" or
94             croak "can not open $outDir/$fn";
95         my $ref;
96         while (<$src>) {
97             if (/^\s*\@DOCSTRING (.*)\@$/) {
98                 $ref = $1;
99             } else {
100                 print {$dst} $_;
101                 next;
102             }
103             if ($verbose) {
104                 print "\t$fn: $ref\n";
105             }
106             if (defined $docstrings{$ref}) {
107                 print {$dst} $docstrings{$ref};
108             } else {
109                 croak "unable to find docstring: $ref";
110             }
111         }
112         close $src or croak "$!";
113         close $dst or croak "$!";
114     }
115     closedir $dir;
116 }