#!/usr/bin/perl
use strict;
use Mysql;
use Env qw(LSBUSER LSBDBPASSWD LSBDB LSBDBHOST);
use Getopt::Long;

sub usage()
{
print STDERR "Usage: mkmodlist -v <lsbversion(s)>\n";
print STDERR "    LSB versions should be comma-separated.\n";
die;
}

my $lsbversion;
GetOptions("v=s" => \$lsbversion);
if( !$lsbversion ) { usage(); }

my $lsbversion_min = "";
my $lsbversion_max = "";
my @lsbversions = sort split(/,/, $lsbversion);
foreach (@lsbversions) {
	$lsbversion_min = $_ if (($lsbversion_min eq "") or ($lsbversion_min > $_));
	$lsbversion_max = $_ if (($lsbversion_max eq "") or ($lsbversion_max < $_));
}

my $dbh = Mysql->connect($LSBDBHOST,$LSBDB,$LSBUSER, $LSBDBPASSWD) || die $Mysql::db_errstr;

my $sth = $dbh->query("SELECT Mname,Mappearedin,Mmandatorysince FROM Module WHERE Mappearedin BETWEEN '1.0' AND '$lsbversion_max' 
			AND Mwithdrawnin IS NULL ORDER BY Mname");
my $flag = 1;
my %defines;
open(my $fd, ">modules.h");

print $fd q(/* GENERATED FILE, DO NOT MODIFY */
#ifndef MODULE_HEADER
#define MODULE_HEADER 1
#include <stdlib.h>

struct lsb_module {
	char *name;
	unsigned int flag;
};

extern struct lsb_module* LSB_Modules[];

);
my $count = 0;
my %desktop_defines;
my @versions_list;
for(1..$sth->numrows) {
	my %row = $sth->fetchhash;
	$row{'Mname'}=~s/-/_/g;
	my $name;
	if(lc(substr($row{'Mname'}, 0, 4)) == "lsb_") {
		$name = "LSB_".ucfirst(substr($row{'Mname'},4));
	} else {
		$name = $row{'Mname'};
	}
	printf $fd "#define $name\t0x%x\n", $flag;
	foreach my $ver (@lsbversions) {
		if ($ver >= $row{'Mappearedin'}) {
			$defines{$ver}->{$row{'Mname'}} = $name;
		}
		if( ($row{'Mmandatorysince'} ne "") and ($row{'Mmandatorysince'} le $ver) ) {
			if (!defined($desktop_defines{$ver})) {
				$desktop_defines{$ver} = [];
			}
			push (@{$desktop_defines{$ver}}, $name);
		}
	}
	$flag <<= 1;
	$count++;
}
$count = (2 ** ($count + 8 - ($count % 8))) - 1;
printf $fd "#define LSB_Core_Modules 	(LSB_Core | LSB_Cpp)\n";
foreach my $ver (@lsbversions) {
	my $v = $ver;
	$v =~ s/\.//g;
	printf $fd "#define LSB_Desktop_Modules_LSB$v (%s)\n", join(" | ", @{$desktop_defines{$ver}});
	push (@versions_list, "_LSB$v");
}
printf $fd "#define LSB_All_Modules 0x%x\n\nextern int LSB_Desktop_Modules[];\n\n#endif\n", $count;
close($fd);
open($fd, ">modules.c");

print $fd q(/* GENERATED FILE, DO NOT MODIFY */
#include "modules.h"

);

print $fd "int LSB_Desktop_Modules[] = {LSB_Desktop_Modules".join(", LSB_Desktop_Modules", @versions_list)."};\n\n";

foreach (@lsbversions) {
	my $v = $_;
	$v =~ s/\.//g;
	print $fd "struct lsb_module LSB_Modules_LSB".$v."[] = {\n";

	print $fd "\t{\"LSB_All_Modules\",\tLSB_All_Modules},\n";
	print $fd "\t{\"LSB_Modules\",\tLSB_Desktop_Modules_LSB$v},\n";
	print $fd "\t{\"LSB_Core_Modules\",\tLSB_Core_Modules},\n";
	foreach my $row (sort keys %{$defines{$_}}) {
#		my $name = pop(@defines);
#		my $row = pop(@defines);
		print $fd "\t{\"$row\",\t".$defines{$_}->{$row}."},\n";
	}
	print $fd "\t{NULL, 0},\n};\n\n";
}

print $fd "struct lsb_module* LSB_Modules[] = {LSB_Modules".join(", LSB_Modules", @versions_list)."};\n";

close($fd);
