#!/usr/bin/perl -w # NAME: fgsetfile.pl # AIM: Process a FG *-set.xml file and try to find the model ac file, and # load it into ac3dview.exe # 2017-04-15 - Added display of sim/multiplay/generic/[int|float|string] # 10/01/2015 - Search harder for 'relative' model file # ============================================================================== # 02/11/2014 - Also see F:\FG\18\fgxmlset - hfgxmlsetf.bat and hfgxmlsetmf.bat # for a C/C++ implementation # ============================================================================= # Also see: F:\FG\18\fgxmlset - hfgxmlsetf.bat and hfgxmlsetmf.bat - A C/C++ aero-set.xml parser # 07/05/2013 geoff mclane http://geoffair.net/mperl use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use File::Spec; # File::Spec->rel2abs($rel); use XML::Simple; use Data::Dumper; use Cwd; my $os = $^O; my $perl_dir = '/home/geoff/bin'; my $PATH_SEP = '/'; my $temp_dir = '/tmp'; if ($os =~ /win/i) { $perl_dir = 'C:\GTools\perl'; $temp_dir = $perl_dir; $PATH_SEP = "\\"; } unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl' Check paths in \@INC...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $temp_dir.$PATH_SEP."temp.$pgmname.txt"; open_log($outfile); my $act_file = $temp_dir.$PATH_SEP."tempactive.txt"; my $xml_set = $temp_dir.$PATH_SEP."tempxmlset.txt"; # user variables my $VERS = "0.0.4 2017-04-18"; ###my $VERS = "0.0.3 2015-01-10"; ###my $VERS = "0.0.2 2014-11-02"; ###my $VERS = "0.0.1 2013-03-17"; my $load_log = 0; my $in_file = ''; my $verbosity = 0; my $out_file = ''; my $fg_root = ''; # 20170415 - Use this X;\fgdata default my $ac3dview = "ac3d_browser2"; # 20150110: was "ac3dview"; my $fgxmlset = "fgxmlset"; # see hfgxmlsetmf.bat my $run_browser = 0; my $run_xmlset = 0; # ### DEBUG ### my $debug_on = 0; my $def_fgroot = 'X:\fgdata'; # 'C:\FG\fgdata'; my $def_file = 'C:\FG\fgdata\Aircraft\TBM-Avenger\avenger-set.xml'; ##my $def_file = 'C:\FG\fgdata\Aircraft\sgs233\sgs233-set.xml'; #my $def_file = $def_fgroot.'\Aircraft\747-200\747-200-set.xml'; #my $def_file = 'C:\FG\fgdata\Aircraft\AG-14\AG-14-set.xml'; #my $def_fgroot = 'C:\FG\fgdata-2.9.0'; #my $def_file = 'C:\FG\fgdata-2.9.0\Aircraft\SenecaII\SenecaII-panelonly-set.xml'; ### program variables my @warnings = (); my $cwd = cwd(); sub VERB1() { return $verbosity >= 1; } sub VERB2() { return $verbosity >= 2; } sub VERB5() { return $verbosity >= 5; } sub VERB9() { return $verbosity >= 9; } sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { prt( "\nNo warnings issued.\n\n" ) if (VERB9()); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub process_in_file($); my @mprefs = (); sub add_2_mprefs($$) { my ($mgs,$rf) = @_; my ($tmp); if (defined ${$rf}{'n'}) { if (defined ${$rf}{'alias'}) { $tmp = $mgs."[".${$rf}{'n'}."] = ".${$rf}{'alias'}; push(@mprefs,$tmp); } elsif (defined ${$rf}{'content'}) { $tmp = $mgs."[".${$rf}{'n'}."] = ".${$rf}{'content'}; push(@mprefs,$tmp); } elsif (defined ${$rf}{'type'}) { $tmp = $mgs."[".${$rf}{'n'}."] = ".${$rf}{'type'}; push(@mprefs,$tmp); } else { prtw("Warning: $mgs ref does NOT contain 'alias', 'type', or 'content'!\n"); prt(Dumper($rf)); $load_log = 1; } } else { prtw("Warning: $mgs ref does NOT contain 'n'!\n"); prt(Dumper($rf)); $load_log = 1; } } sub process_mp_generics($) { my $sim = shift; my ($rt); if (defined ${$sim}{'multiplay'}) { my $mp = ${$sim}{'multiplay'}; if (ref($mp) eq 'HASH') { if (defined ${$mp}{'generic'}) { my $gen = ${$mp}{'generic'}; #prt(Dumper($gen)); #$load_log = 1; if (defined ${$gen}{'float'}) { my $gf = ${$gen}{'float'}; my $mgfl = "sim/multiplay/generic/float"; my ($rf); $rt = ref($gf); if ($rt eq 'ARRAY') { ###prt(Dumper($gf)); foreach $rf (@{$gf}) { add_2_mprefs($mgfl,$rf); } # $load_log = 1; } elsif ($rt eq 'HASH') { add_2_mprefs($mgfl,$gf); } } if (defined ${$gen}{'int'}) { my $gi = ${$gen}{'int'}; my $mgi = "sim/multiplay/generic/int"; my ($ri); #prt(Dumper($gi)); $rt = ref($gi); if ($rt eq 'ARRAY') { foreach $ri (@{$gi}) { add_2_mprefs($mgi,$ri); } } elsif ($rt eq 'HASH') { add_2_mprefs($mgi,$gi); } #$load_log = 1; } if (defined ${$gen}{'string'}) { my $gs = ${$gen}{'string'}; my $mgs = "sim/multiplay/generic/string"; my ($rs); if (ref($gs) eq 'HASH') { add_2_mprefs($mgs,$gs); } elsif (ref($gs) eq 'ARRAY') { foreach $rs (@{$gs}) { add_2_mprefs($mgs,$rs); } } else { prt(Dumper($gs)); $load_log = 1; } } } } # prt(Dumper($mp)); # $load_log = 1; } } sub process_in_file($) { my ($inf) = @_; prt("Processing [$inf]...\n"); if (! -f $inf) { prtw("WARNING: Can NOT locate [$inf]!\n"); return; } my $xml = XMLin($inf); my ($ff,$sim,$mod,$tmp); my ($name,$dir) = fileparse($inf); ut_fix_directory(\$dir); my $rt = ref($xml); prt("Got ref = $rt\n"); ### prt(Dumper($xml)); ### $load_log = 1; ### pgm_exit(1,"TEMP EXIT\n"); my $path = ''; if ($rt eq 'HASH') { if (defined ${$xml}{'include'}) { $tmp = ${$xml}{'include'}; $ff = $dir.$tmp; if (-f $ff) { process_in_file($ff); } else { prtw("Warning: Can NOT locate '$tmp', in dir $dir!\n"); } } if (defined ${$xml}{'sim'}) { $sim = ${$xml}{'sim'}; $rt = ref($sim); if ($rt eq 'HASH') { process_mp_generics($sim); if (defined ${$sim}{'model'}) { $mod = ${$sim}{'model'}; $rt = ref($mod); if ($rt eq 'HASH') { if (defined ${$mod}{'path'}) { $path = ${$mod}{'path'}; $rt = ref($path); if ($rt eq 'HASH') { if (defined ${$path}{'content'}) { $path = ${$path}{'content'}; $rt = ref($path); if ($rt eq 'HASH') { $path = ''; } elsif ($rt eq 'ARRAY') { $path = ''; } } else { prt("No 'content' for this HASH\n"); $path = ''; } } elsif ($rt eq 'ARRAY') { $path = ''; } } } elsif ($rt eq 'ARRAY') { foreach $tmp (@{$mod}) { $rt = ref($tmp); if ($rt eq 'HASH') { if (defined ${$tmp}{'path'}) { $path = ${$tmp}{'path'}; $rt = ref($path); if ($rt eq 'HASH') { $path = ''; } elsif ($rt eq 'ARRAY') { $path = ''; } else { last; } } } } } else { prt("\$mod = \${\$xml}{'sim'}{'model'}; NOT a HASH/ARRAY! got [$rt]\n"); } } elsif (defined ${$xml}{'include'}) { my $inc = ${$xml}{'include'}; prt("Got an include file [$inc]\n"); $rt = ref($inc); if ($rt eq '') { $ff = $fg_root.$PATH_SEP.$inc; if (-f $ff) { process_in_file($ff); return; } $ff = $dir.$inc; if (-f $ff) { process_in_file($ff); return; } } else { prt("Found 'include' as [$rt]\n"); } } else { prt("\${\$xml}{'sim'}{'model'}, ['multiplay'], nor {'include'}; NOT defined\n"); } if (length($path) == 0) { prt("Using \${\$xml}{'sim'}{'model'} and {'include'}; failed to get 'path'\n") } } else { prt("\$sim = \${\$xml}{'sim'}; NOT a HASH! got $rt\n"); } } else { prt("Failed to find 'sim' in the HASH ref from $inf!\n"); } } else { prt("XMLin gave $rt instead of a HASH!\n"); } #if (defined ${$xml}{'sim'}{'model'}{'path'}) { # my $path = ${$xml}{'sim'}{'model'}{'path'}; if (length($path)) { $ff = $fg_root.$PATH_SEP.$path; if ($os =~ /win/i) { $ff = path_u2d($ff); } else { $ff = path_d2u($ff); } # WARNING: Given path 'Systems/NAVandGSfilters.xml' # unable to find file 'X:\fgdata\Systems\NAVandGSfilters.xml' if (! -f $ff) { $tmp = $dir.$path; if (-f $tmp) { $ff = $tmp; } } if (! -f $ff) { my ($n,$d) = fileparse($path); $tmp = $dir.$n; if (-f $tmp) { $ff = $tmp; } } if (-f $ff) { ##my ($n2,$d2) = fileparse($ff); my ($n2,$d2,$e2) = fileparse($ff, qr/\.[^.]*/); ut_fix_directory(\$d2); if ($e2 eq '.ac') { write2file("$ff\n",$act_file); prt("Written $act_file\n"); prt("Got MODEL file $ff, passing to '$ac3dview', if run_browser=$run_browser (-r) \n"); system("$ac3dview $ff") if ($run_browser); } else { prt("Loading MODEL XML $ff\n"); my $xml2 = XMLin($ff); if (defined ${$xml2}{'path'}) { my $path2 = ${$xml2}{'path'}; my $ff2 = $d2.$path2; if (-f $ff2) { write2file("$ff2\n",$act_file); prt("Written $act_file\n"); prt("Got MODEL file $ff2, passing to '$ac3dview', if run_browser=$run_browser (-r)\n"); system("$ac3dview $ff2") if ($run_browser); } else { # MODEL file X:\fgdata\Aircraft\777\Models\Aircraft/777/Models/777-200ER.ac NOT FOUND my $ff3 = $fg_root.$PATH_SEP.$path2; if (-f $ff3) { write2file("$ff3\n",$act_file); prt("Written $act_file\n"); prt("Got MODEL file $ff3, passing to '$ac3dview', if run_browser=$run_browser (-r)\n"); system("$ac3dview $ff3") if ($run_browser); } else { prt("Got path=$path2, root=$fg_root, and directory=$d2\n"); prt("MODEL file $ff2 and $ff3 NOT FOUND\n"); } } } elsif (defined ${$xml2}{'include'}) { my $inc2 = ${$xml2}{'include'}; my $ff3 = $d2.$inc2; if (-f $ff3) { prt("Loading include file $ff3\n"); my $xml3 = XMLin($ff3); if (defined ${$xml3}{'path'}) { my $path3 = ${$xml3}{'path'}; my $ff4 = $d2.$path3; if (-f $ff4) { write2file("$ff4\n",$act_file); prt("Written $act_file\n"); prt("Got Model file $ff4, passing to '$ac3dview', if run_browser=$run_browser (-r)\n"); system("$ac3dview $ff4") if ($run_browser); } else { prt("path file $ff4 NOT FOUND\n"); } } else { prt("No 'path' in include file $ff3\n"); } } else { prt("include file $ff3 NOT FOUND\n"); } } else { prtw("WARNING: Can NOT locate 'path' in XML!\n"); if (VERB9()) { prt(Dumper($xml2)); $load_log = 1; prt("Failed to locate 'path' in XML!\n"); } } } } else { prtw("WARNING: Can NOT locate file $ff!\nfg_root=$fg_root, path=$path\n"); } } else { prt("FAILED to locate 'path' in XML!\n"); if (VERB9()) { prt(Dumper($xml)); $load_log = 1; } } } sub process_in_setfile($) { my $fil = shift; my $cmd = "$fgxmlset -o $xml_set $fil"; prt("Running: '$cmd'\n"); system($cmd); } ######################################### ### MAIN ### parse_args(@ARGV); process_in_file($in_file); process_in_setfile($in_file) if ($run_xmlset); if (@mprefs) { prt("\nGot ".scalar @mprefs." multiplay generic references from file(s)...\n"); prt(join("\n",@mprefs)."\n"); } else { prt("No multiplay generic references found in file(s)...\n"); } pgm_exit(0,""); ######################################## sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have a following argument!\n") if (!@av); } sub parse_args { my (@av) = @_; my ($arg,$sarg,@arr,$fnd,$tmp); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^v/) { if ($sarg =~ /^v.*(\d+)$/) { $verbosity = $1; } else { while ($sarg =~ /^v/) { $verbosity++; $sarg = substr($sarg,1); } } prt("Verbosity = $verbosity\n") if (VERB1()); } elsif ($sarg =~ /^l/) { if ($sarg =~ /^ll/) { $load_log = 2; } else { $load_log = 1; } prt("Set to load log at end. ($load_log)\n") if (VERB1()); } elsif ($sarg =~ /^r/) { $run_browser = 1; } elsif ($sarg =~ /^x/) { $run_xmlset = 1; } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_file = $sarg; prt("Set out file to [$out_file].\n") if (VERB1()); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { ###$in_file = $arg; $in_file = File::Spec->rel2abs($arg); # get ABSOLUTE path of input if (! -f $in_file) { pgm_exit(1,"Error: Unable to 'stat' file '$in_file'\n Check name, location ($arg)\n"); } prt("Set input to [$in_file]\n") if (VERB1()); ##@arr = split(/(\\|\/)/,$in_file); @arr = split("\\".$PATH_SEP,$in_file); $sarg = ''; $fnd = 0; foreach $tmp (@arr) { ###prt("$tmp\n"); $sarg .= $PATH_SEP if (length($sarg)); $sarg .= $tmp; if (-f $sarg.$PATH_SEP.'version') { $fnd = 1; last; } } ##prt("$sarg\n"); ##pgm_exit(1,""); if ($fnd > 0) { $fg_root = $sarg; prt("Set FG_ROOT to [$fg_root]\n") if (VERB1()); } else { $sarg = $def_fgroot.$PATH_SEP.'version'; if (length($def_fgroot) && (-d $def_fgroot) && (-f $sarg)) { $fg_root = $def_fgroot; } else { prtw("WARNING: FG_ROOT not found using $in_file!\n"); } } } shift @av; } if ($debug_on) { prtw("WARNING: DEBUG is ON!\n"); if (length($in_file) == 0) { $in_file = $def_file; prt("Set DEFAULT input to [$in_file]\n"); } } if (length($in_file) == 0) { give_help(); pgm_exit(1,"ERROR: No input files found in command!\n"); } if (! -f $in_file) { pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n"); } if (length($fg_root) == 0) { $fg_root = $def_fgroot; prt("Set DEFAULT FG_ROOT to [$fg_root]\n"); } } sub give_help { prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] in-file\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --verb[n] (-v) = Bump [or set] verbosity. def=$verbosity\n"); prt(" --load (-l) = Load LOG at end. ($outfile)\n"); prt(" --run (-r) = Run the command $ac3dview to view ac file.\n"); prt(" --xecute (-x) = Also pass file to $fgxmlset (see hfgxmlsetmf.bat)\n"); prt(" --out (-o) = Write output to this file.\n"); prt("\n"); prt(" Given a FG -set.xml, try to find the model files, and if found load\n"); prt(" in $ac3dview EXE. Also pass XML to $fgxmlset EXE for processing.\n"); prt(" Uses XML::Simple for file parsing.\n"); prt("\n"); #prt(" See fgsetfile.pl to process a FG *-set.xml file and try to find the model ac file...\n"); prt(" See findset.pl, scan the input directory for 'aero'-set.xml files, and output the list found.\n"); prt(" See fgsetlist.pl, which perversely does the same as the above file!!!\n"); prt(" Can use fgxmlset.exe, hfgxmlsetmf.bat, to view contents of the 'set' files.\n"); prt(" See fgaclist.pl to output the full list of *.ac files found in a directory.\n"); prt(" See findmodel.pl to scan dir looking for model ac files.\n"); prt(" See findac.pl, scan dir for model .ac file and output a list, like fgaclist.pl.\n"); prt("\n"); } # eof - fgsetfile.pl