#!/usr/bin/perl -w # ## Created for the third time from scratch (I lost the first two iterations ## in hard drive crashes) on May 26 1997 -- Brandon Gillespie ## ## This does not just accept the defined textdump format, it ONLY accepts ## the named textdump format from Genesis-1.1-STABLE, mainly because I'm ## lazy and really thats all you should be using for this. Furthermore, ## its not very forgiving about whitespace, as a standard textdump should ## be. If your textdump has been manually altered from whatever Genesis ## would normally output, you should run it through a compile/decompile ## with coldcc first. ## ## -Brandon ## if ($] < 5) { die("This program requires perl 5.002 or greater.\n"); } $ver = "1.0"; $help = "brandon\@cold.org"; $syn = "Syntax: $0 [-t=textdump] [-s=srcdir]"; $input = "textdump"; $src = "src"; $showstatus = 1; while ($#ARGV != -1) { $_ = shift; if (/^-t/) { if (s/^-t=//) { $input = $_; } else { $input = shift || die("$syn\nNo followup argument to '-t'\n"); } } elsif (/^-s/) { if (s/^-s=//) { $src = $_; } else { $src = shift || die("$syn\nNo followup argument to '-s'\n"); } } elsif (/^-q/) { $showstatus = 0; } else { die("$syn\nInvalid argument '$_'\n"); } } $core = "$src/+CORE"; $idx = "$src/+INDEX"; select(STDOUT); $| = 1; sub abort { $msg = $_[0]; $msg =~ s/\n/\n\*\* /; die("\n** $msg\n** Aborted.. Contact $help for help.\n"); } if (!-e $src) { mkdir($src, 0755); } elsif (!-d $src) { die("Source location '$src' exists but is not a directory.\n"); } elsif (!-w $src) { die("Source location '$src' exists but is not writable.\n"); } open(IDX, ">$idx") || die("Unable to open index: $!\n"); open(CORE, ">$core") || die("Unable to open core index: $!\n"); ## where is input coming from print "Textdump Splitter and Sorter version $ver\nSplitting '$input' into '$src'\n"; open(IN, $input) || die("Unable to open input file '$input': $!\n"); ### progress meter: just guess really well, no reason to spend lots ### of time making it absolutely correct. my $avglines = -s $input; ## average 45 chars per line *shrug* $avglines = ($avglines / 45) / 50; $printed =0; if ($showstatus) { print " 0% |-------25%-------------50%--------------75%-------| 100%\r"; print "Progress: 0% |"; } my $next = $avglines; sub finish_progress { if ($showstatus) { while ($printed < 50) { $printed++; print "#"; } print "\n"; } } sub progress { if ($showstatus) { if ($next <= $.) { ## abort.. die, our averages were off? ($printed == 49) && return; print "#"; $next += $avglines; $printed++; } } } ## lets have at it $obj = ""; $parents = ""; $file = ""; %vars = (); %methods = (); %mcode = (); %natives = (); $ISCORE = 0; while (<IN>) { chomp; if (!$_) { next; } s/^new //; ############################################################### ### object ############################################################### if (s/^object //) { print_object(); progress(); if (/^#(\d+)/) { abort("Object #$1 without name found at line $.\n(Or this textdump wasn't created with the -# option to coldcc)"); } if (!s/^\$([a-z0-9_]+)[;:]//i) { abort("Unable to identify object at line $."); } $obj = $1; $parents = $_; $parents =~ s/^\s+//; $parents =~ s/;$//; $file = "$src/${obj}.cdc"; if (-e $file) { abort("File already exists for object $obj, perhaps this textdump has\nalready been decompiled?"); } next; } !$file && abort("Directives found before object definition\n"); ############################################################### ### variables ############################################################### if (s/^var //) { if (/^\$root flags = /) { if (/'core[],]/) { $ISCORE = 1; } else { $ISCORE = 0; } } if (/^\$has_commands local /) { s/ = #\[\[/ = \\\n #[[/; s/\]\]\]\]\]\]\], +/]]]]]]],\\\n /g; s/\n (\["[^"]+",) \[\[/\n $1\\\n [[/gm; } if (!s/^\$([a-z0-9_]+)\s+//i) { &warn("Invalid ancestor found defining variable, ignoring"); next; } $def = $1; if (!s/^([a-z0-9_]+)\s+=\s+//i) { &warn("Invalid variable definition, ignoring"); next; } $var = $1; s/;$//; $data = $_; $key = "${def}:${var}"; if (exists($vars{$key})) { abort("Bug? Key $key already exists in vars dict"); } $vars{$key} = $data; next; } ############################################################### ### natives ############################################################### if (/^bind_native\s+\.([a-z0-9_]+)\(\)\s+\.([a-z0-9_]+)\(\)/i) { $native = $1; $alt = $2; $natives{$native} = $alt; next; } ############################################################### ### method ############################################################### if (s/^(root|driver|frob|private|public|protected)\s+method\s+//) { $access = $1; if (!s/\.([a-z0-9_]+)\(\)\s*//i) { abort("Invalid method definition"); } $method = $1; $end = ""; if (/:\s*([^{;]+)([{;])/) { $flags = $1; $end = $2; } elsif (/\s*([{;])/) { $flags = ""; $end = $1; } else { abort("Method not terminated correctly"); } $key = "$method"; if (exists($methods{$key})) { abort("Bug? Key $key already exists in method dict"); } $methods{$key} = "$access:$flags"; $code = ""; if ($end eq "{") { $terminated = 0; while (<IN>) { if (/^};$/) { $terminated = 1; last; } $code .= $_; } if (!$terminated) { abort("Textdump ends in method definition"); } } $mcode{$key} = $code; next; } abort("Unknown directive: $_\n"); } print_object(); finish_progress(); sub print_object { !$obj && return; if ($ISCORE) { print CORE "$obj\n"; } else { print IDX "$obj\n"; } open(OUT, ">$file") || abort("Unable to open $file: $!"); print OUT "\n"; if ($obj ne "root" && $obj ne "sys") { print OUT "new "; } print OUT "object \$$obj"; if ($parents) { print OUT ": $parents"; } print OUT ";\n\n"; for $key (sort(keys(%vars))) { ($def, $var) = split(/:/, $key); print OUT "var \$$def $var = $vars{$key};\n"; } print OUT "\n"; for $key (sort(keys(%methods))) { ($access, $flags) = split(/:/, $methods{$key}); $code = $mcode{$key}; print OUT "$access method .$key()"; if ($flags) { print OUT ": $flags"; } if ($code) { print OUT " {\n$code};\n\n"; } else { print OUT ";\n\n"; } } for $key (sort(keys(%natives))) { print OUT "bind_native .$key() .$natives{$key}();\n"; } print OUT "\n"; close(OUT); %vars = (); %methods = (); %mcode = (); %natives = (); $ISCORE = 0; } sub warn { $msg = $_[0]; print(STDERR "\bLine $.: $msg\n"); }