#!/usr/bin/perl
# gperf-build-prop-set.pl --
#   Script for parsing gperf file and generating jmap_property_set_t
# SPDX-License-Identifier: BSD-3-Clause-CMU
# See COPYING file at the root of the distribution for more details.
#
# Input: gperf file
# Output: C declarations
#
# The Gperf file is parsed and generates the following:
#
#   - Static arrays of the wildcard, mandatory, and always_get
#     subsets of the defined properties
#   - A jmap_property_set_t for the object type
#

use strict;
use warnings;
use File::Basename;

my $filename = shift or die "Usage: $0 filename\n";

open(my $fh, '<', $filename) or die "Could not open file '$filename': $!\n";

my $in_c_code   = 0;
my $in_keywords = 0;
my $obj_type    = "";

my %special_props = (
    'wildcards'  => [],
    'always_get' => [],
    'mandatory'  => []
);

while (my $line = <$fh>) {
    chomp $line;
    
    # Skip %{ ... %} C code inclusion
    if ($line =~ /^%\{/) { $in_c_code = 1; next; }
    if ($line =~ /^%\}/) { $in_c_code = 0; next; }
    if ($in_c_code) { next; }
    
    # Skip comments
    next if $line =~ /^\s*#/;

    # Parse Gperf declarations
    if ($line =~ /^%define\s+word-array-name\s+(.+)_prop_array/) {
        $obj_type = $1;
        next;
    }

    # Detect keywords section (%% separator)
    if ($line =~ /^%%/) {
        $in_keywords = !$in_keywords;
        next;
    }
    
    # Parse keywords entries and separate special properties into arrays
    if ($in_keywords && $line =~ /\S/) {
        # Format: name, field1, $field2
        my @fields = split(/\s*,\s*/, $line);

        if ($fields[0] =~ /".+\*"/) {
            push(@{$special_props{'wildcards'}}, $fields[0]);
        }
        elsif ($fields[2] =~ /JMAP_PROP_ALWAYS_GET/) {
            push(@{$special_props{'always_get'}}, $fields[0]);
        }
        elsif ($fields[2] =~ /JMAP_PROP_MANDATORY/) {
            push(@{$special_props{'mandatory'}}, $fields[0]);
        }
    }
}
close($fh);


# Output comment block
my $scriptname = basename($0);
my ($name, $dir, $suffix) = fileparse($filename, qr/\.[^.]*/);

print <<EOF;
/*
 * $name.h -
 *   Property set (perfect hash & special arrays) for '$obj_type'
 * SPDX-License-Identifier: BSD-3-Clause-CMU
 * See COPYING file at the root of the distribution for more details.
 *
 * Code produced by:
 *   $scriptname $name$suffix
 */

EOF


# Output special property arrays
my $have_array = 0;
foreach my $array_name ('wildcards', 'always_get', 'mandatory') {
    my @array = @{$special_props{$array_name}};

    next if (!scalar(@array));

    if (!$have_array) {
        print "/* Arrays of the special property subsets */\n";
        $have_array = 1;
    }

    print "static const char *const ${obj_type}_${array_name}_array[] = {\n   ";

    foreach my $prop_name (@array) {
        print " ${prop_name},";
    }
    print "\n};\n\n";
}


# Output jmap_property_set_t
my $uc_obj_type = uc($obj_type);

print <<EOF;
/* Generated by Gperf and defined in $name.c */
extern const jmap_prop_hash_table_t jmap_${obj_type}_props_map;

/* Complete set of properties */
static const jmap_property_set_t ${obj_type}_props = {
    &jmap_${obj_type}_props_map,
    /* const strarray_t */
EOF

my $len = length($obj_type) + 17;

foreach my $array_name ('wildcards', 'always_get', 'mandatory') {
    my $count = scalar(@{$special_props{$array_name}});
    my $array = !$count ? "NULL /* $array_name */" :
        "${obj_type}_${array_name}_array";

    printf("    { % 2d, 0, (char **) %-*.*s },\n", $count, $len, $len, $array);
}
print "};\n";

exit 0;
