#!/usr/bin/php4 -qC ------------------------------------------------------------------------------- $Id$ -----------------------------------------------------------------------------*/ // CONVERTS A STRING TO XML ENTITIES {{{ function xmlentities($s) { return str_replace( array('&', '"', '<', '>'), array('&', '"', '<', '>'), $s); } // }}} //TAG's XML {{{ $xmi_start = << EOT; $xmi_half = << EOT2; $xmi_end = << EOT3; //}}} //TEMPLATES XMI {{{ $umlclass = ''; $umlclass_c = ''; $umloperation = ''; $umloperation_c = ''; $umlparameter = ''; $umlattribute = ''; $umllistitem = ''; $umllistitem_c = ''; //}}} //GLOBALS {{{ $ID = 0; //Global ID $IDPARAM = 0; //Functions parameter ID $ARRAY = array(); //Array with information obtained from the code file //}}} //GETTING DATA FROM FILES {{{ for ($j = 1; $j < count($argv); $j++) { $file = $argv[$j]; if (is_dir($file)) { $dh = opendir($file); while (($f = readdir($dh)) !== false) { if (is_readable("$file/$f") and substr($f, -4) == '.php') { $argv[] = "$file/$f"; } } closedir($dh); continue; } //PARSING INFORMATION {{{ elseif (is_readable($file) and substr($file, -4) == '.php') { $cont = file ($file); $DOCUMENTING = false; $options = array (); $cont_param = -1; foreach ($cont as $line) { $line = trim ($line); $tmp = preg_split ('/[^\w_\/\*\@\$\&\.\']+/', $line); //DOCUMENTING? {{{ if ($tmp['0'] == '/**') { //Starts documentation $DOCUMENTING = true; $doc_param = 0; //If 1 the line belongs to a parameter documentation } if ($tmp['0'] == '*/') { //Ends documentation $DOCUMENTING = false; $doc_param = 0; } //}}} //Parse documentation {{{ if ($DOCUMENTING) { $tmp2 = ltrim ($line,'* /**'); //Removes * or /** from the beginning of the line $action = substr($tmp2, 0, strpos($tmp2,' ')); //Gets the action (evrerything before the @) $action = ($action === '') ? $tmp2 : $action; $value = trim(strstr($tmp2, ' ')); //Action value //SWITCH ACTION {{{ switch ($action) { case '@access' : switch ($value) { case 'private' : $options['access'] = 201; break; case 'protected': $options['access'] = 202; break; default : $options['access'] = 200; } $doc_param = 0; break; case '@package' : $options['package'] = $value; $doc_param = 0; break; case '@abstract': $options['abstract'] = 1; $doc_param = 0; break; case '@static' : $options['static'] = 1; $doc_param = 0; break; case '@var' : $options['type'] = substr($value, 0, strpos($value,' ')); $doc_param = 0; break; case '@return' : $type = substr($value, 0, strpos($value,' ')); $rest = (strpos($value,' ')) ? substr($value, strpos($value,' ')) : ''; if ($type === '') { $type = $value; } if (strtolower($type) == 'object') { $rest = trim($rest); $type = substr($rest, 0, strpos($rest,' ')); $rest = (strpos($rest,' ')) ? substr($rest, strpos($rest,' ')) : ''; } $options['type'] = $type; //If there is more documentation, I add it to the main documentation if (trim($rest)) { $options['documentation'].= "Returns: ".xmlentities(trim($rest))."\n"; } $doc_param = 0; $rest = ''; break; case '@param' : $cont_param++; $type = substr($value, 0, strpos($value,' ')); $rest = substr($value, strpos($value,' ') + 1); if (strtolower($type) == 'object') { $rest = trim($rest); $type = substr($rest, 0, strpos($rest,' ')); $rest = substr($rest, strpos($rest,' ') + 1); } $options['param'][$cont_param]['type'] = $type; $options['param'][$cont_param]['documentation'] = xmlentities(trim(substr(trim($rest), strpos(trim($rest), ' ')))); $doc_param = 1; break; default: $tmp2 = xmlentities($tmp2); if (@$doc_param) { $options['param'][$cont_param]['documentation'].= "\n".$tmp2; } else { @$options['documentation'].= $tmp2."\n"; } } //}}} } //}}} //CLASS {{{ if (!$DOCUMENTING && $tmp['0'] == 'class') { $ID++; $IDCLASS = $ID; $ARRAY[$ID]['id'] = $ID; $ARRAY[$ID]['name'] = $tmp['1']; $ARRAY[$ID]['stereotype'] = (@$options['stereotype']) ? $options['stereotype'] : ''; $ARRAY[$ID]['package'] = (@$options['package']) ? $options['package'] : ''; $ARRAY[$ID]['abstract'] = (@$options['abstract']) ? $options['abstract'] : 0; $ARRAY[$ID]['documentation'] = (@$options['documentation']) ? $options['documentation'] : ''; $ARRAY[$ID]['static'] = (@$options['static']) ? $options['static'] : 0; $ARRAY[$ID]['scope'] = (@$options['access']) ? $options['access'] : 200; $ARRAY[$ID]['operations'] = array(); $ARRAY[$ID]['attributes'] = array(); $options = array(); } //}}} //FUNCTION {{{ if (!$DOCUMENTING && $tmp['0'] == 'function') { $ID++; if ($tmp['1']{0} == '&') { $tmp['1'] = substr($tmp['1'], 1); //Removes the & $options['type'] = (@$options['type']) ? '&'.$options['type'] : ''; } if ($tmp['1']{0} == '_') { $tmp['1'] = substr($tmp['1'], 1); //Removes the _ } $ARRAY[$IDCLASS]['operations'][$ID]['id'] = $ID; $ARRAY[$IDCLASS]['operations'][$ID]['name'] = $tmp['1']; $ARRAY[$IDCLASS]['operations'][$ID]['stereotype'] = (@$options['stereotype']) ? $options['stereotype'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['package'] = (@$options['package']) ? $options['package'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['abstract'] = (@$options['abstract']) ? $options['abstract'] : 0; $ARRAY[$IDCLASS]['operations'][$ID]['documentation'] = (@$options['documentation']) ? $options['documentation'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['static'] = (@$options['static']) ? $options['static'] : 0; $ARRAY[$IDCLASS]['operations'][$ID]['scope'] = (@$options['access']) ? $options['access'] : 200; $ARRAY[$IDCLASS]['operations'][$ID]['type'] = (@$options['type']) ? $options['type'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['param'] = array(); //PARAMETERS {{{ $param_line = trim(substr(strstr($line,'('),0),'{ '); //Removes the last { $param = parseParenthesis($param_line); $i = 0; foreach ($param as $par) { if ($par['name']{0} == '$'|| $par['name']{0} == '&') { //If starts with $ or & switch ($par['name']{0}) { case '$': $par['name'] = substr($par['name'], 1); //Removes the $ break; case '&': $par['name'] = substr($par['name'], 2); //Removes the & and the $ $options['param'][$i]['type'] = (@$options['param'][$i]['type']) ? '&'.$options['param'][$i]['type'] : ''; break; } $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['id'] = $i; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['name'] = $par['name']; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['stereotype'] = (@$options['param'][$i]['stereotype']) ? $options['param'][$i]['stereotype'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['package'] = (@$options['param'][$i]['package']) ? $options['param'][$i]['package'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['abstract'] = (@$options['param'][$i]['abstract']) ? $options['param'][$i]['abstract'] : 0; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['documentation'] = (@$options['param'][$i]['documentation']) ? $options['param'][$i]['documentation'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['static'] = (@$options['param'][$i]['static']) ? $options['param'][$i]['static'] : 0; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['scope'] = (@$options['param'][$i]['access']) ? $options['param'][$i]['access'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['type'] = (@$options['param'][$i]['type']) ? $options['param'][$i]['type'] : ''; $ARRAY[$IDCLASS]['operations'][$ID]['param'][$i]['value'] = (@$par['value']) ? $par['value'] : ''; } $i++; } //}}} $options = array(); $cont_param = -1; $i = 0; } //}}} //ATRIBUTTES {{{ if (!$DOCUMENTING && $tmp['0'] == 'var') { $ID++; $tmp['1'] = substr($tmp['1'], 1); //Removes the $ if ($tmp['1']{0} == '_') { $tmp['1'] = substr($tmp['1'],1); //Removes the _ if (!(@$options['access'])) { $options['access'] = 201; } } //Check for default values if (array_key_exists('2',$tmp)) { $options['value'] = $tmp['2']; } $ARRAY[$IDCLASS]['attributes'][$ID]['id'] = $ID; $ARRAY[$IDCLASS]['attributes'][$ID]['name'] = $tmp['1']; $ARRAY[$IDCLASS]['attributes'][$ID]['stereotype'] = (@$options['stereotype']) ? $options['stereotype'] : ''; $ARRAY[$IDCLASS]['attributes'][$ID]['package'] = (@$options['package']) ? $options['package'] : ''; $ARRAY[$IDCLASS]['attributes'][$ID]['abstract'] = (@$options['abstract']) ? $options['abstract'] : 0; $ARRAY[$IDCLASS]['attributes'][$ID]['documentation'] = (@$options['documentation']) ? $options['documentation'] : ''; $ARRAY[$IDCLASS]['attributes'][$ID]['static'] = (@$options['static']) ? $options['static'] : 0; $ARRAY[$IDCLASS]['attributes'][$ID]['scope'] = (@$options['access']) ? $options['access'] : 200; $ARRAY[$IDCLASS]['attributes'][$ID]['type'] = (@$options['type']) ? $options['type'] : ''; $ARRAY[$IDCLASS]['attributes'][$ID]['value'] = (@$options['value']) ? $options['value'] : ''; $options = array(); } //}}} } } //}}} } //}}} //WRITES XMI FILE {{{ $m =fopen ('./umlOut.xmi', 'w'); fwrite($m, $xmi_start); $LISTITEM = ''; //CLASS foreach ($ARRAY as $ar) { //Prepare class line $tmp2 = $umlclass; fwrite($m, preg_replace (array ('/##STEREOTYPE##/','/##PACKAGE##/','/##ID##/','/##ABSTRACT##/','/##DOCUMENTATION##/','/##NAME##/', '/##STATIC##/','/##SCOPE##/'), array ($ar['stereotype'],$ar['package'],$ar['id'],$ar['abstract'],trim($ar['documentation']),$ar['name'], $ar['static'],$ar['scope']), $tmp2)."\n"); //Prepare class listitem line $tmp2 = $umllistitem; $LISTITEM.= preg_replace (array('/##TYPE##/','/##LABEL##/','/##ID##/'),array(813, $ar['name'], $ar['id']),$tmp2)."\n"; //FUNCTIONS foreach ($ar['operations'] as $op) { $tmp2 = $umloperation; fwrite($m, preg_replace (array('/##STEREOTYPE##/','/##PACKAGE##/','/##ID##/','/##TYPE##/','/##ABSTRACT##/','/##DOCUMENTATION##/', '/##NAME##/','/##STATIC##/','/##SCOPE##/'), array($op['stereotype'],$op['package'],$op['id'],$op['type'],$op['abstract'],trim($op['documentation']), $op['name'],$op['static'],$op['scope']) , $tmp2)."\n"); //PARAMETERS //Parameters aren't listed in listview foreach ($op['param'] as $pa) { $tmp2 = $umlparameter; fwrite ($m, preg_replace(array('/##STEREOTYPE##/','/##PACKAGE##/','/##ID##/','/##TYPE##/','/##ABSTRACT##/','/##DOCUMENTATION##/', '/##NAME##/','/##STATIC##/','/##SCOPE##/','/##VALUE##/'), array($pa['stereotype'],$pa['package'],$pa['id'],$pa['type'],$pa['abstract'],trim($pa['documentation']), $pa['name'],$pa['static'],$pa['scope'],$pa['value']), $tmp2)."\n"); } fwrite($m,$umloperation_c."\n"); //Pepare function lisitem line $tmp2 = $umllistitem; $LISTITEM.= preg_replace (array('/##TYPE##/','/##LABEL##/','/##ID##/'),array(815, $op['name'], $op['id']),$tmp2)."\n"; $LISTITEM.=$umllistitem_c."\n"; } //ATTRIBUTES foreach ($ar['attributes'] as $op) { $tmp2 = $umlattribute; fwrite($m, preg_replace(array('/##STEREOTYPE##/','/##PACKAGE##/','/##ID##/','/##TYPE##/','/##ABSTRACT##/','/##DOCUMENTATION##/', '/##NAME##/','/##STATIC##/','/##SCOPE##/','/##VALUE##/'), array($op['stereotype'],$op['package'],$op['id'],$op['type'],$op['abstract'],trim($op['documentation']),$op['name'], $op['static'],$op['scope'],$op['value']), $tmp2)."\n"); //Prepare attributes listitem line $tmp2 = $umllistitem; $LISTITEM.= preg_replace (array('/##TYPE##/','/##LABEL##/','/##ID##/'),array(814, $op['name'], $op['id']),$tmp2)."\n"; $LISTITEM.=$umllistitem_c."\n"; } fwrite($m,$umlclass_c); $LISTITEM.=$umllistitem_c."\n"; } fwrite($m, $xmi_half. $LISTITEM."\n".$xmi_end); exit; //}}} //parsePARENTHESIS {{{ //This function receives the content between the parenthesis ( with the ( and the ) ) //It's a recursive function //Returns an array of arrays function parseParenthesis($value) { $pos = 0; $content = true; $char = true; $value = substr(substr(trim($value), 1), 0, strrpos(substr(trim($value), 1),')')); //Removes the ( and the ) while ($char) { //I look for the following separation ( , or = ) {{{ //If its an = then I check if the next character is an > if (!strpos($value, ',') && !strpos($value, '=')) { $char = false; } elseif (!strpos($value, ',') && strpos($value, '=')) { if ($value{strpos($value, '=') + 1} == '>') { $char = '=>'; } else { $char = '='; } } elseif (strpos($value, ',') && !strpos($value, '=')) { $char = ','; } elseif (strpos($value, ',') && strpos($value, '=') && strpos($value, ',') > strpos($value, '=')) { if ($value{strpos($value, '=') + 1} == '>') { $char = '=>'; } else { $char = '='; } } elseif (strpos($value, ',') && strpos($value, '=') && strpos($value, ',') < strpos($value, '=')) { $char = ','; } //}}} //Get's the option name {{{ $result[$pos]['name'] = (strpos($value, $char)) ? substr($value, 0, strpos($value, $char)) : $value; $pos_del = strpos($value, $char); //}}} //If $char is an = or an =>, gets the option value {{{ if ($char == '=') { $op_value = (strpos($value, $char)) ? trim(substr($value, strpos($value, $char) + 1)) : false; } elseif ($char == '=>') { $op_value = (strpos($value, $char)) ? trim(substr($value, strpos($value, $char) + 2)) : false; } //}}} //Parse the rest of the line {{{ if ($op_value) { if ($op_value{0} == "'" || $op_value{0} == '"') { $pos_del = parseString($op_value); if ($pos_del == 0) { $result[$pos]['value'] = "''"; } else { $op_value = substr($op_value, 1); $result[$pos]['value'] = substr($op_value, 0, $pos_del); } } elseif (trim(strtolower(substr($op_value, 0 ,5))) == 'array') { //Recursive part {{{ $op_value = trim(substr($op_value, 5)); $op_value = trim(substr($op_value, 1)); //Removes the ( if ($op_value{0} == ')') { $result[$pos]['value'] = 'array()'; } else { //I look for the colsing ) {{{ $subpos = 0; $continue = true; $temp = $op_value; while ($continue) { if (($temp{$subpos} == '"' || $temp{$subpos} == "'") && $temp{$subpos - 1} != '\\') { $pos_del = parseString(substr($temp,$subpos)) + $subpos; $subpos = $pos_del + 2; if (trim($temp{$subpos}) == ')') { $continue = false; } } else { if ($subpos > strlen($temp)) { $continue = false; } $subpos++; } } //}}} $par = parseParenthesis('('.substr($op_value, 0 , $subpos).')'); $result[$pos]['value'] = 'array('; foreach ($par as $p) { $result[$pos]['value'] .= $p['name']; if (@$p['value']) { $result[$pos]['value'] .= '=>\''.$p['value'].'\','; } else { $result[$pos]['value'] .= ','; } } $result[$pos]['value'] = rtrim($result[$pos]['value'],','); $result[$pos]['value'] .= ')'; $pos_del = $subpos; } } //}}} else { //Look for the next parameter. If its the last one //I assign it as it came. if ($pos_del = strpos($op_value, ',')) { $result[$pos]['value'] = ($pos_del) ? trim(substr($op_value, 0, $pos_del)): $op_value; } } $value = $op_value; } //}}} //Removes from $value the part that's alredy parsed {{{ if ($pos_del) { $value = trim(substr(trim($value), $pos_del + 2)); } if (!$value) { $char = false; } //}}} $pos++; $op_value=''; } return $result; } //}}} //parseString {{{ //Funtion that parse the content between "" or '' //Returns the position of the final ' or " function parseString($value) { $result = -1; $ii = 1; $cont = true; switch ($value{0}) { //{{{ case "'": $char = "'"; break; case '"': $char = '"'; break; }//}}} $value = substr($value, 1); //Removes the ' or the " from the beginning of the string if ($value{0} == $char) { $result = 0; } else { while ($cont) { //{{{ $ii++; if ($value{$ii} == $char) { if ($value{$ii - 1} != '\\') { $cont = false; $result = $ii; } } }//}}} } return $result; } //}}} ?>