15.09.2011, 07:40
Hey,
I've gained interest in SA-MP scripting again; however, I'm a Mac user these days. In a quest to get PAWN syntax highlighting, auto-complete, etc. in TextMate (Mac text editor) I had to get information from the include files. I did manage to get all that working just great.
Anyway, at the bottom of this post is the script I ended up using. I figured someone might find it useful.
You give the function a string containing, for example, all your PAWN include files together. The function will return an array with tags, defines, and functions.
Example output: http://pastebay.com/138441
A short example of usage:
The above code would output:
The script:
I've gained interest in SA-MP scripting again; however, I'm a Mac user these days. In a quest to get PAWN syntax highlighting, auto-complete, etc. in TextMate (Mac text editor) I had to get information from the include files. I did manage to get all that working just great.
Anyway, at the bottom of this post is the script I ended up using. I figured someone might find it useful.
You give the function a string containing, for example, all your PAWN include files together. The function will return an array with tags, defines, and functions.
Example output: http://pastebay.com/138441
A short example of usage:
PHP Code:
<?php
require_once 'pawn_parser.php';
function get_dir_contents($dir, $skip = array())
{
$data = '';
$skip = array_flip(array_merge($skip, array('.', '..', '.DS_Store', 'Thumbs.db')));
if (!is_dir($dir)) {
return '';
}
if (($d = dir($dir)) === false) {
return '';
}
$path = $d->path;
while (false !== ($entry = $d->read())) {
if (isset($skip[$entry])) {
continue;
}
$entry = "$path/$entry";
if (is_dir($entry)) {
$data .= get_dir_contents($entry, $skip);
} else if (is_file($entry)) {
$data .= file_get_contents($entry) . "\n";
}
}
$d->close();
return $data;
}
$include_data = get_dir_contents('include'); // you gotta change this
$include_info = parse_pawn_includes($include_data);
foreach ($include_info->functions as $function) {
if ($function->type == 'forward') {
echo "Callback: $function->name<br/>\n";
}
}
?>
Code:
Callback: OnNPCModeInit Callback: OnNPCModeExit Callback: OnNPCConnect Callback: OnNPCDisconnect Callback: OnNPCSpawn Callback: OnNPCEnterVehicle Callback: OnNPCExitVehicle Callback: OnClientMessage Callback: OnPlayerDeath Callback: OnPlayerText Callback: OnPlayerStreamIn Callback: OnPlayerStreamOut Callback: OnVehicleStreamIn Callback: OnVehicleStreamOut Callback: OnRecordingPlaybackEnd Callback: OnGameModeInit Callback: OnGameModeExit Callback: OnFilterScriptInit Callback: OnFilterScriptExit Callback: OnPlayerConnect Callback: OnPlayerDisconnect Callback: OnPlayerSpawn Callback: OnPlayerDeath Callback: OnVehicleSpawn Callback: OnVehicleDeath Callback: OnPlayerText Callback: OnPlayerCommandText Callback: OnPlayerRequestClass Callback: OnPlayerEnterVehicle Callback: OnPlayerExitVehicle Callback: OnPlayerStateChange Callback: OnPlayerEnterCheckpoint Callback: OnPlayerLeaveCheckpoint Callback: OnPlayerEnterRaceCheckpoint Callback: OnPlayerLeaveRaceCheckpoint Callback: OnRconCommand Callback: OnPlayerRequestSpawn Callback: OnObjectMoved Callback: OnPlayerObjectMoved Callback: OnPlayerPickUpPickup Callback: OnVehicleMod Callback: OnEnterExitModShop Callback: OnVehiclePaintjob Callback: OnVehicleRespray Callback: OnVehicleDamageStatusUpdate Callback: OnPlayerSelectedMenuRow Callback: OnPlayerExitedMenu Callback: OnPlayerInteriorChange Callback: OnPlayerKeyStateChange Callback: OnRconLoginAttempt Callback: OnPlayerUpdate Callback: OnPlayerStreamIn Callback: OnPlayerStreamOut Callback: OnVehicleStreamIn Callback: OnVehicleStreamOut Callback: OnDialogResponse Callback: OnPlayerClickPlayer Callback: @receivestring Callback: @receivepacket
PHP Code:
<?php
function oneLineEnumerations($input)
{
return preg_replace('/\s+/', ' ', $input[0]);
}
function parse_pawn_includes($input) {
$input = preg_replace('#/\*[\s\S]*?\*/#', '', $input);
$input = preg_replace('#//.*#', '', $input);
$input = preg_replace_callback('/enum[\s\S]*?{[\s\S]*?}/', 'oneLineEnumerations', $input);
$functions = array();
$bad_args = array();
$all_tags = array();
$constants = array_flip(array('floatround_round', 'floatround_floor', 'floatround_ceil', 'floatround_tozero', 'floatround_unbiased', 'seek_start', 'seek_current', 'seek_end', 'EOS', 'cellbits', 'cellmax', 'cellmin', 'charbits', 'charmin', 'charmax', 'ucharmax', '__Pawn', 'debug', 'overlaysize', 'radian', 'degrees', 'grades'));
foreach ($constants as $constant => $v) {
$constants[$constant] = true;
}
foreach (explode("\n", $input) as $line) {
$line = trim($line);
if (empty($line)) {
continue;
}
if (preg_match('/^(native|forward)/', $line)) {
if (preg_match('/^(native|forward)\s+(?:([\S]+)\s*:\s*)?([^(]+)\s*\(\s*([^;]*)\s*\)\s*;/', $line, $matches)) {
$type = $matches[1];
$tag = $matches[2];
$name = $matches[3];
$arguments = $matches[4];
if (preg_match('/^operator.$/', $name)) {
continue;
}
$arguments = preg_split('/\s*,(?![^{]+})\s*/', $arguments);
$arguments_parsed = array();
foreach ($arguments as &$argument) {
if (empty($argument)) {
continue;
}
if (preg_match('/(const)?\s*(&)?\s*(?:([^:]+?)\s*:\s*)?(\.\.\.|\.\.|[@a-zA-Z0-9_]+)(\[.*\])?(?:.*=\s*(.+))?/', $argument, $matches)) {
$arguments_match = array(
'line' => $matches[0],
'const' => $matches[1] == 'const',
'reference' => $matches[2] == '&',
'tags' => $matches[3],
'name' => $matches[4],
'length' => @$matches[5],
'default' => @$matches[6],
);
if (preg_match('/{\s*(.*)\s*}/', $arguments_match['tags'], $matches)) {
$arguments_match['tags'] = preg_split('/\s*,\s*/', $matches[1]);
foreach ($arguments_match['tags'] as $tag) {
$all_tags[$tag] = true;
}
} else {
$arguments_match['tags'] = trim($arguments_match['tags']);
if (!empty($arguments_match['tags'])) {
$all_tags[$arguments_match['tags']] = true;
$arguments_match['tags'] = array($arguments_match['tags']);
} else {
$arguments_match['tags'] = array();
}
}
if (!empty($arguments_match['length'])) {
if (preg_match('/\[\s*(\S+)\s*\]/', $arguments_match['length'], $matches)) {
$arguments_match['length'] = (string) $matches[1];
} else {
$arguments_match['length'] = true;
}
} else {
$arguments_match['length'] = null;
}
$arguments_parsed[] = (object) $arguments_match;
} else {
$bad_args[] = $line;
}
}
unset($argument);
$functions[] = (object) array(
'type' => $type,
'tag' => $tag,
'name' => $name,
'arguments' => $arguments_parsed,
);
} else {
//echo 'ERROR: ' . $line . "\n";
}
} else if (preg_match('/^#define\s+(\S+)\s*(\S+)?\s*/i', $line, $matches)) {
$constants[$matches[1]] = isset($matches[2]) ? $matches[2] : true;
}
}
return array(
'functions' => $functions,
'constants' => $constants,
'tags' => array_keys($all_tags),
);
}
?>