#!/usr/bin/env perl
# Simple script for substitute placeholders in Texinfo files with
# docstring values found in source code.
# Copyright (C) 2020-2025 Sergey Matveev <stargrave@stargrave.org>
#
# If you C source code contains:
#
#     // TEXINFO: SomeKey
#     // ...
#     // last line of docstring
#     some C code
#
# Then under "SomeKey" you will have the whole docstring (starting from
# the line after "TEXINFO", till "last line"). You can include its
# contents (excluding comment characters) in your .texi files placing
#
#     @DOCSTRING SomeKey@

use strict;
use warnings;
use Carp q{croak};

my $verbose = 0;
if ($ARGV[0] eq q{-v}) {
    $verbose = 1;
    shift @ARGV;
}
my $outDir = $ARGV[0];
my @srcDirs = split /:/, $ARGV[1];
my @docDirs = split /:/, $ARGV[2];
my @exts = (defined $ENV{EXTS}) ? (split / /, $ENV{EXTS}) : qw{c h h.in};
my %docstrings;

foreach my $srcDir (@srcDirs) {
    if ($verbose) {
        print "src: $srcDir\n";
    }
    opendir my $dir, $srcDir or croak "can not open $srcDir";
    foreach my $fn (readdir $dir) {
        foreach (@exts) {
            if ($fn =~ /[.]$_$/) {
                goto ExtIsGood;
            }
        }
        next;
    ExtIsGood:
        open my $src, q{<:encoding(UTF-8)}, "$srcDir/$fn" or croak "can not open $srcDir/$fn";
        my $curEntry;
        while (<$src>) {
            chomp;
            if (not /^\/\//) {
                if (defined $curEntry) {
                    undef $curEntry;
                }
                next;
            }
            s/^\/\/[ ]?//;
            if (/^TEXINFO: (.*)$/) {
                $curEntry = $1;
                $docstrings{$curEntry} = q{};
                if ($verbose) {
                    print "\t$fn: $curEntry\n";
                }
                next;
            }
            if (defined $curEntry) {
                $docstrings{$curEntry} .= "$_\n";
            }
        }
        close $src or croak "$!";
    }
    closedir $dir;
}

foreach my $docDir (@docDirs) {
    if ($verbose) {
        print "doc: $docDir\n";
    }
    opendir my $dir, $docDir or croak "can not open $docDir";
    if ($docDir !~ /[\/]$/) {
        $docDir .= q{/};
    }
    if ($docDir eq q{./}) {
        $docDir = q{};
    }
    foreach my $fn (readdir $dir) {
        if ($fn !~ /[.]texi$/) {
            next;
        }
        $fn = $docDir . $fn;
        open my $src, q{<:encoding(UTF-8)}, $fn or croak "can not open $fn";
        mkdir "$outDir/$docDir";
        open my $dst, q{>:encoding(UTF-8)}, "$outDir/$fn" or
            croak "can not open $outDir/$fn";
        my $ref;
        while (<$src>) {
            if (/^\s*\@DOCSTRING (.*)\@$/) {
                $ref = $1;
            } else {
                print {$dst} $_;
                next;
            }
            if ($verbose) {
                print "\t$fn: $ref\n";
            }
            if (defined $docstrings{$ref}) {
                print {$dst} $docstrings{$ref};
            } else {
                croak "unable to find docstring: $ref";
            }
        }
        close $src or croak "$!";
        close $dst or croak "$!";
    }
    closedir $dir;
}
