The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use Data::Dumper;
use Getopt::Long;
use Getopt::Long;
use Carp;
use FindBin qw($Bin);
use lib "$Bin/../lib";
use Cwd;
use Cwd 'abs_path';

$idre = $id = qr'(?:[a-zA-Z_][a-zA-Z_0-9:\.]*)';
$RE_balanced_squarebrackets =    qr'(?:[\[]((?:(?>[^\[\]]+)|(??{$RE_balanced_squarebrackets}))*)[\]])';
$RE_balanced_smothbrackets =     qr'(?:[\(]((?:(?>[^\(\)]+)|(??{$RE_balanced_smothbrackets}))*)[\)])';
$RE_balanced_brackets      =     qr'(?:[\{]((?:(?>[^\{\}]+)|(??{$RE_balanced_brackets}))*)[\}])';
$RE_comment_Cpp =                q{(?:\/\*(?:(?!\*\/)[\s\S])*\*\/|\/\/[^\n]*\n)};

Getopt::Long::Configure(qw(bundling));
GetOptions(\%OPT,qw{
d+
quite|q+
verbose|v+
outfile|o=s
}, @g_more) or usave(\*STDERR);

sub readfile {
    my ($in) = @_;
    usage(\*STDOUT) if (length($in) == 0) ;
    open IN, "$in" or die "Reading \"$in\":".$!;
    local $/ = undef;
    $m = <IN>;
    close IN;
    return $m;
}

$m = readfile ($ARGV[0]);

sub delspace { my ($m) = @_; $m =~ s/^\s+//s; $m; }
sub rmspace  { my ($m) = @_; $m =~ s/^\s+//s; $m =~ s/\s+$//s; $m; }
sub nrmspace { my ($m) = @_; $m =~ s/\s+/ /s; rmspace($m); }
sub unspace  { my ($m) = @_; $m =~ s/\s+/_/s; $m; }
sub dbgstr   { my ($m,$l) = @_; $m =~ s/\n/\\n/g; return substr($m, 0, $l).(length($m)>$l?"...":""); }
sub ident    { my ($ctx) = @_; my $r = ""; for (my $i = 0; $i < $$ctx{'i'}; $i++) { $r .= "|"; }; return $r; }

while ($m =~ /($idre)$RE_balanced_smothbrackets:\s*\n/m) {
  my ($id, $typ) = ($1,$2);
  $m = $';
  #  print (STDERR "$id,$typ\n"); 
  my @m = ();
  while (($m =~ /^((?:[ \t]+[^\n]*\n))/s)) {
    $m = $'; my $l = $1;
    #print ".".$l.":";
    if ($l =~ /(.+)\s+:\s+($idre)(.*)/) {
      my ($t,$n,$r) = ($1,$2,$3); $t = nrmspace($t);
      my $p = $n,;
      $p =~ s/\./_/g;
      my $a = {};
      if ($r =~ /$RE_balanced_brackets/) {
	eval ("\$a = { $1 };");
      }
      push(@m,{'n'=>nrmspace($n),'t'=>nrmspace($t),'a'=>$a});
      my $newpre = "";my $newpost = "";      
      my $gnewpre = "";my $gnewpost = "";      
      my $derefget = ""; my $derefset = ""; 
      if (defined($$a{'new'})) {
	  $newpre = "new_${t}(";
	  $newpost = ")";
	  $gnewpre = "->m";
	  $gnewpost = "";
      }
      if (defined($$a{'deref'})) {
	  $derefget = "&"; 
	  $derefset = "*";
      }
      my $vpost = $$a{'vpost'};
      my $name = $$a{'n'} ? $$a{'n'} : $p;

      my $ne;
      if (($ne = $$a{'array'})) {
	my $nn = $$ne[0];
	my $nt = $$ne[1];
	my $ni = $$ne[2];

	  

my $g = "
MODULE = C::sparse   PACKAGE = ${id}
PROTOTYPES: ENABLE

void
${name}(p,...)
        $typ p
    PREINIT:
        void *ptr; int i = 0;
        ${t}_t l; SPARSE_CTX_GEN(0);
    PPCODE:
        /*printf(\"e:%p x:%p %p\\n\",p->m, p->m->$n, p->m->$n->next);*/
        $ni; l = (${t}_t)(p->m->$n);
 	if (GIMME_V == G_ARRAY) {
	    while(l && !$nt(l)) {
	        EXTEND(SP, 1);
	        PUSHs(bless_${t}((${t}_t)l));
                l = l->$nn;
            }
        } else {
            EXTEND(SP, 1);
	    while(l && !$nt(l)) { i++; l = l->$nn; };
            PUSHs(sv_2mortal(newSViv(i)));
        }

";
      print $g;

      } elsif ($$a{'arrlist'}) {

my $g = "
MODULE = C::sparse   PACKAGE = ${id}
PROTOTYPES: ENABLE

void
${name}(p,...)
        $typ p
    PREINIT:
        struct ptr_list *l; void *ptr; int i = 0;
    PPCODE:
        l = (struct ptr_list *)(p->m->$n);
 	if (GIMME_V == G_ARRAY) {
	    FOR_EACH_PTR(l, ptr) {
	        EXTEND(SP, 1);
	        PUSHs(bless_${t}((${t}_t)ptr));
            } END_FOR_EACH_PTR(ptr);
        } else {
            EXTEND(SP, 1);
	    FOR_EACH_PTR(l, ptr) { i++; } END_FOR_EACH_PTR(ptr);
            PUSHs(sv_2mortal(newSViv(i)));
        }

";
      print $g;

      } else {
      
my $g = "
MODULE = C::sparse   PACKAGE = ${id}
PROTOTYPES: ENABLE

".nrmspace($t)." $vpost
${name}(p)
        $typ p
    PREINIT:
    CODE:
        RETVAL = ${newpre}${derefget}p->m->$n${newpost};
    OUTPUT:
	RETVAL
";
      print $g;

      my $cast = $$a{'cast'};

my $s = "
void
set_${name}(p,v)
        $typ p
        ".nrmspace($t)." ${vpost}v
    PREINIT:
    CODE:
        p->m->$n = ${derefset}$cast v${gnewpre};
";
      print $s;


      }
    }
  }
  
}