public function compile() { $this->clean_directories(); if (file_exists('gamemodes/build-info.txt')) { unlink('gamemodes/build-info.txt'); } register_shutdown_function(array($this, 'clean_directories')); $start_time = microtime(true); $this->generate_main(); $pawnc = new PAWNC(); $pawnc->base_dir = 'gamemodes'; $pawnc->input_file = 'gamemodes/main.pwn'; $pawnc->output_file = 'gamemodes/main.amx'; $pawnc->include_dir = 'include'; $pawnc->debug = $this->cfg['debug_level']; $pawnc->list_file = false; $pawnc->short_output_paths = true; $pawnc->args['IN_COMPILE_SCRIPT'] = true; if (!$this->is_windows) { if (false === stripos(`ps aux`, 'wineserver')) { echo "Starting wineserver.. "; `{$pawnc->wine_dir}/wineserver -p -d0`; `{$pawnc->wine_dir}/wine cmd /c exit`; echo "done.\n"; } } $retval = 0; //exit; $retval = $pawnc->compile(); if (!empty($pawnc->output)) { // Replace module prefixes back to the module's name in the compiler's output $pawnc->output = preg_replace_callback('/M([0-9]+)@/', array($this, 'pawnc_module_prefix'), $pawnc->output); echo "{$pawnc->output}\n\n"; } if ($retval != 0) { echo "Failed to compile ({$retval}).\n"; if (file_exists('gamemodes/build-info.txt')) { unlink('gamemodes/build-info.txt'); } } else { if (!$pawnc->list_file && !$pawnc->asm_file) { $amx = new AMX($pawnc->output_file); $save = false; $pat = '/^M([0-9]+)@/'; $redirects = array(); $this_errfunc = 0; @date_default_timezone_set(date_default_timezone_get()); $buildinfo = array('Date: ' . date('r') . "\n", 'AMX size: ' . $this->human_size($amx->header->size)); foreach ($amx->header->publics as &$public) { if ($public->name == 'PBP_ThisFunctionError') { $this_errfunc = $public->value; break; } } foreach ($amx->header->publics as &$public) { if (preg_match($pat, $public->name)) { $name = preg_replace_callback($pat, array($this, 'pawnc_module_prefix'), $public->name); if (strlen($name) > 31) { continue; } $redirects[$name] = true; array_push($amx->header->publics, (object) array('name' => $name, 'value' => $public->value)); if ($this_errfunc) { $name = preg_replace($pat, 'this.', $public->name); if (strlen($name) > 31) { continue; } $redirects[$name] = true; array_push($amx->header->publics, (object) array('name' => $name, 'value' => $this_errfunc)); } } } if ($amx->debug) { $pat = '/^M([0-9]+)@/'; $uservars = array(); $configvars = array(); $staticgroups = array(); $commands = array(); foreach ($amx->header->publics as $entry) { if (isset($redirects[$entry->name])) { continue; } if (preg_match('/^(.*)@Pu_$/', $entry->name, $matches)) { $uservars[] = preg_replace_callback($pat, array($this, 'pawnc_module_prefix'), $matches[1]); } if (preg_match('/^(.*)@Pc_$/', $entry->name, $matches)) { $configvars[] = preg_replace_callback($pat, array($this, 'pawnc_module_prefix'), $matches[1]); } if (preg_match('/^@pG_(.*)$/', $entry->name, $matches)) { $staticgroups[] = preg_replace_callback($pat, array($this, 'pawnc_module_prefix'), $matches[1]); } if (preg_match('/^@_yC(.*)$/', $entry->name, $matches)) { $commands[$matches[1]] = ''; } $matching_symbol = false; foreach ($amx->debug->symbols as &$symbol) { if ($symbol->ident == AMX::IDENT_FUNCTION && $symbol->name == $entry->name) { $matching_symbol = true; break; } } if (!$matching_symbol) { echo "NOTICE: Public {$entry->name} has no found matching symbol.\n"; } } if (!empty($configvars)) { $buildinfo[] = "\nConfig variables:\n\t* " . implode("\n\t* ", $configvars); } if (!empty($staticgroups)) { $buildinfo[] = "\nStatic groups:\n\t* " . implode("\n\t* ", $staticgroups); } if (!empty($uservars)) { $buildinfo[] = "\nUser variables:\n\t* " . implode("\n\t* ", $uservars); } $commandsstr = "\nCommands:"; $maxcmdlen = 0; foreach ($commands as $command => &$description) { $len = strlen($command); if (isset($this->command_descriptions[$command])) { $description = $this->command_descriptions[$command]; } if ($len > $maxcmdlen) { $maxcmdlen = $len; } } unset($description); foreach ($commands as $command => $description) { if (!empty($description)) { $description = " - {$description}"; } $commandsstr .= sprintf("\n\t* %s%s", str_pad($command, $maxcmdlen), $description); } $buildinfo[] = $commandsstr; $arrays = array(); foreach ($amx->debug->symbols as &$symbol) { if ($symbol->ident == AMX::IDENT_ARRAY) { $arrays[] =& $symbol; } // Replace module prefixes back to the module's name in the AMX file's debug information $symbol->name = preg_replace_callback($pat, array($this, 'pawnc_module_prefix'), $symbol->name, -1, $count); } foreach ($amx->debug->tags as $id => &$tag) { $tag = preg_replace_callback($pat, array($this, 'pawnc_module_prefix'), $tag, -1, $count); } foreach ($amx->debug->automatons as &$automaton) { $automaton->name = preg_replace_callback($pat, array($this, 'pawnc_module_prefix'), $automaton->name, -1, $count); } foreach ($amx->debug->states as &$state) { $state->name = preg_replace_callback($pat, array($this, 'pawnc_module_prefix'), $state->name, -1, $count); } if (!$this->is_windows) { $base = escapeshellarg(realpath('.')); $base = trim(`{$pawnc->wine_dir}/winepath -w {$base}`); } else { $base = realpath('.'); } $base = str_replace('\\', '/', $base); $base = rtrim($base, '/'); foreach ($amx->debug->files as &$file) { $file->name = str_replace('\\', '/', $file->name); $file->name = preg_replace('#^' . preg_quote($base, '#') . '#', '', $file->name); // This will most likely only happen when in UNC paths (Windows tries to fix that..) if (preg_match('#^[a-z]:/#i', $file->name) && preg_match('#^[a-z]:/#i', $base)) { $file->name = preg_replace('#^[a-z]:/' . preg_quote(substr($base, 3)) . '#i', '', $file->name); } $file->name = ltrim($file->name, '/'); do { $file->name = preg_replace('#(^|/)([^/]*?)/\\.\\.(/|$)#', '$1', $file->name, -1, $count); } while ($count); } usort($arrays, function ($left, $right) { $leftsize = 1; $rightsize = 1; foreach ($left->dim as $dim) { $leftsize *= $dim->size; } foreach ($right->dim as $dim) { $rightsize *= $dim->size; } return $rightsize - $leftsize; }); $topvars = "\n\nLargest variables:"; for ($i = 0; $i < 30; $i++) { if (!isset($arrays[$i])) { break; } $symbol =& $arrays[$i]; $symbol->size = 1; foreach ($symbol->dim as $dim) { $symbol->size *= $dim->size; } $topvars .= "\n\t" . sprintf("%6s - %s", $this->human_size($symbol->size * 4, 0), $symbol->name); } if (file_exists('gamemodes/build-info.txt')) { $fp = fopen('gamemodes/build-info.txt', 'a'); fwrite($fp, $topvars); fclose($fp); } $save = true; } if ($save) { if (!$amx->save()) { echo "ERROR: Failed to save the modified AMX. It might be corrupted."; } } file_put_contents('gamemodes/build-info.txt', implode("\n", $buildinfo) . "\n\n" . file_get_contents('gamemodes/build-info.txt')); echo "Successfully compiled in " . round(microtime(true) - $start_time, 1) . " seconds; AMX size: " . $this->human_size($amx->header->size) . ".\n"; } else { echo "Done.\n"; } } }