name = $name;
$this->return_type = preg_replace("/\*/", "", $return_type);
for ($i = 0; $i < count($return_type); $i++) {
if ($return_type[$i] == '*') {
$this->ptr++;
}
}
}
public function getReturnType()
{
return $this->return_type;
}
public function isResourceCreator()
{
if (count($this->args)) {
$first = $this->args[0];
if (preg_match("/out/", $first->getName())) {
return true;
}
} else {
if (preg_match("/git_/", $this->getReturnType())) {
return true;
}
}
return false;
}
public function isStringCreator()
{
if (preg_match("/(char)/", $this->getReturnType())) {
return true;
}
}
public function isLongCreator()
{
if (preg_match("/(size_t|int)/", $this->getReturnType())) {
return true;
}
}
public function isArrayCreator()
{
if (preg_match("/git_/", $this->getReturnType())) {
return true;
}
}
public function isVoidCreator()
{
if (preg_match("/void/", $this->getReturnType())) {
return true;
}
}
public function isSavior()
{
if (preg_match('/_free$/', $this->getName())) {
return true;
}
}
public function isCallbacker()
{
foreach($this->args as $arg) {
if (preg_match("/_cb$/", $arg->getType())) {
return true;
}
if (preg_match("/callback$/", $arg->getType())) {
return true;
}
if (preg_match("/packbuilder_progress/", $arg->getType())) {
return true;
}
}
return false;
}
public function getArguments()
{
return $this->args;
}
public function addArgument(Arg $arg)
{
$this->args[] = $arg;
}
public function getName()
{
return $this->name;
}
public function first()
{
return $this->args[0];
}
}
class Arg
{
protected $type;
protected $ptr = 0;
protected $name;
protected $const;
public function getDefaultValue()
{
if (preg_match("/long/", $this->getZendType())) {
return "0";
} else {
return "NULL";
}
}
public function getName()
{
return $this->name;
}
public function setName($name)
{
return $this->name = $name;
}
public function getType()
{
return $this->type;
}
public function isCallback()
{
if (preg_match("/_cb$/", $this->getType())) {
return true;
}
if (preg_match("/callback$/", $this->getType())) {
return true;
}
if (preg_match("/packbuilder_progress/", $this->getType())) {
return true;
}
if (preg_match("/git_push_transfer_progress/", $this->getType())) {
return true;
}
return false;
}
public function getPtr()
{
return str_repeat("*", $this->ptr - 1);
}
public function shouldWrite()
{
if ($this->ptr == 2) {
if (preg_match("/^git_/", $this->type)) {
return true;
}
}
return false;
}
public function getZendType()
{
if (preg_match("/char/", $this->type)) {
return "char";
} else if (preg_match("/(size_t|int)/", $this->type)) {
return "long";
} else if (preg_match("/git_oid/", $this->type)) {
return "char";
} else if (preg_match("/git_otype/", $this->type)) {
return "long";
} else if (preg_match("/^git_/", $this->type)) {
return "zval";
} else if (preg_match("/payload/", $this->name)) {
return "zval";
} else {
error_log(sprintf("%s (zendtype)", $this->type));
}
}
public function __construct($type, $name)
{
$this->type = $type;
$this->name = $name;
for ($i = 0; $i < strlen($name); $i++) {
if ($name[$i] == '*') {
$this->ptr++;
}
}
$this->name = preg_replace("/\*/", "", $this->name);
if (preg_match("/^const/", $this->type)) {
$this->const = 1;
$this->type = preg_replace("/^const\s+/", "", $this->type);
}
}
}
class StringStream
{
protected $buffer = "";
public function __construct($string = "")
{
$this->buffer = $string;
}
public function append($string)
{
$this->buffer .= $string;
}
public function assign($message)
{
$this->buffer = $message;
}
public function __toString()
{
return $this->buffer;
}
}
class ZeroCopyOutputStream
{
protected $stream;
public function __construct($stream)
{
$this->stream = $stream;
}
public function write($message)
{
$this->stream->append($message);
}
}
class Printer
{
protected $replace;
protected $level = 0;
protected $indent_char = "\t";
protected $stream;
protected $next;
public function __construct($stream, $replace)
{
$this->stream = $stream;
$this->replace = $replace;
}
public function block(Callable $call)
{
$this->indent();
$call($this);
$this->outdent();
}
public function indent()
{
$this->level++;
}
public function outdent()
{
$this->level--;
if ($this->level < 0) {
throw new RuntimeException("too low indent level.");
}
}
public function put($message/* $args */)
{
$args = func_get_args();
array_shift($args);
$key = "";
$value = "";
$tmp = array();
if (count($args)) {
if (count($args) % 2 != 0) {
throw new InvalidArgumentException("parameter doesn't match");
}
for ($i = 0; $i < count($args); $i++) {
if ($i % 2 == 0) {
$key = $args[$i];
} else {
$value = $args[$i];
$tmp[$key] = $value;
unset($key);
unset($value);
}
}
foreach ($tmp as $key => $value) {
$message = str_replace(sprintf("%s%s%s", $this->replace, $key, $this->replace), $value, $message);
}
}
if ($this->next) {
$this->stream->write(str_repeat($this->indent_char, $this->level));
}
if (preg_match('/\n$/m', $message)) {
$this->next = true;
} else {
$this->next = false;
}
$this->stream->write($message);
}
}
class Fashion
{
protected $name;
protected $flag;
public function __construct($name, $flag = false)
{
$this->name = basename($name, ".h");
$this->flag = $flag;
}
public function shouldResource(Arg $arg)
{
static $types;
if (!$types) {
$types = array(
"git_repository",
"git_commit",
"git_tree",
"git_tree_entry", // really?
"git_blob",
"git_revwalk",
"git_treebuilder",
"git_reference",
"git_config",
"git_object",
"git_index",
"git_odb",
"git_refdb",
"git_status_list",
"git_branch_iterator",
"git_tag",
"git_cred",
"git_transport",
"git_remote",
"git_merge_head",
"git_merge_result",
"git_pathspec",
"git_pathspec_match_list",
"git_diff",
"git_patch",
"git_diff_hunk",
"git_filter_list",
"git_buf",
"git_filter_source",
"git_diff_line",
"git_reference_iterator",
"git_config_iterator",
"git_index_conflict_iterator",
"git_transport*",
"git_transport",
"git_note",
"git_note_iterator",
"git_odb",
"git_odb_object",
"git_odb_backend",
"git_odb_stream",
"struct git_odb",
"git_reflog",
"git_reflog_entry",
"git_blame",
"git_packbuilder",
"git_submodule",
"git_push",
"git_refspec",
"git_filter",
"git_indexer",
);
}
if (in_array($arg->getType(), $types)) {
return true;
} else {
return false;
}
}
public function getReturnType(Func $f)
{
if ($f->isResourceCreator()) {
return "resource";
} else {
if (preg_match("/(int|size_t)/", $f->getReturnType())) {
return "long";
} else if (preg_match("/git_signature/", $f->getReturnType())) {
return "array";
} else if (preg_match("/git/", $f->getReturnType())) {
return "resource";
} else if (preg_match("/void/", $f->getReturnType())) {
return "void";
} else if (preg_match("/char/", $f->getReturnType())) {
return "string";
} else {
error_log(sprintf("%s does not support yet", $f->getReturnType()));
}
}
}
public function generateProto(Printer $printer, Func $f)
{
$printer->put("/* {{{ proto `return_type` `function`",
"return_type", $this->getReturnType($f),
"function", $f->getName()
);
$printer->put("(");
$cnt = count($f->getArguments());
$i = 0;
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($i == 0 && $f->isResourceCreator()) {
$i++;
continue;
}
if ($arg->shouldWrite()) {
$i++;
continue;
}
if ($this->shouldResource($arg)) {
$printer->put("resource");
} else {
if (preg_match("/char/", $arg->getType())) {
$printer->put("string");
} else if (preg_match("/(int|size_t)/", $arg->getType())) {
$printer->put("long");
} else if (preg_match("/(git_oid)/", $arg->getType())) {
$printer->put("string");
} else if (preg_match("/(git_signature)/", $arg->getType())) {
$printer->put("array");
} else if (preg_match("/(git_strarray)/", $arg->getType())) {
$printer->put("array");
} else if (preg_match("/_cb$/", $arg->getType())) {
$printer->put("Callable");
} else if (preg_match("/git_otype/", $arg->getType())) {
$printer->put("long");
} else {
error_log(sprintf("# unknown type (%s)", $arg->getType()));
}
}
$printer->put(" ");
// variable name
$printer->put("\$`arg`", "arg", $arg->getName());
if ($i +1 < $cnt) {
$printer->put(", ");
}
$i++;
}
$printer->put(")\n");
$printer->put(" */\n");
}
public function isPtr(Arg $arg)
{
if (preg_match("/zval/", $arg->getZendType())) {
return "*";
} else {
if (preg_match("/char/", $arg->getZendType())) {
return "*";
} else {
return "";
}
}
}
public function generateDeclarations(Printer $printer, Func $f)
{
$tables = array();
if ($f->isResourceCreator()) {
$tables["php_git2_t"][] = array(
"name" => "*result",
"value" => "NULL",
);
} else if ($f->isArrayCreator()) {
$tables[$f->getReturnType()][] = array(
"name" => "*result",
"value" => "NULL",
);
if (preg_match("/git_signature/", $f->getReturnType())) {
$tables["zval"][] = array(
"name" => "*__result",
"value" => "NULL",
);
}
} else if ($f->isLongCreator()) {
$tables[$f->getReturnType()][] = array(
"name" => "result",
"value" => "0",
);
} else if ($f->isStringCreator()) {
$tables[$f->getReturnType()][] = array(
"name" => "*result",
"value" => "NULL",
);
}
$i = 0;
$cnt = count($f->getArguments());
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($i == 0 && $f->isResourceCreator()) {
$tables[$arg->getType()][] = array(
"name" => sprintf("%s%s", $arg->getPtr(), $arg->getName()),
"value" => "NULL",
);
$i++;
continue;
}
if ($arg->shouldWrite()) {
$tables[$arg->getType()][] = array(
"name" => sprintf("%s%s", $arg->getPtr(), $arg->getName()),
"value" => "NULL",
);
} else {
/** @var Arg $arg */
$tables[$arg->getZendType()][] = array(
"name" => sprintf("%s%s", $this->isPtr($arg), $arg->getName()),
"value" => $arg->getDefaultValue(),
);
if ($this->shouldResource($arg)) {
$tables["php_git2_t"][] = array(
"name" => sprintf("*_%s", $arg->getName()),
"value" => "NULL",
);
}
if ($arg->getType() == "git_strarray") {
$tables["git_strarray"][] = array(
"name" => sprintf("_%s", $arg->getName()),
"value" => "{0}",
);
}
if (preg_match("/char/", $arg->getZendType())) {
$tables["int"][] = array(
"name" => sprintf("%s_len", $arg->getName()),
"value" => "0",
);
}
}
if ($arg->getType() == "git_oid") {
$tables["git_oid"][] = array(
"name" => sprintf("__%s", $arg->getName()),
"value" => "{0}",
);
}
$i++;
}
if ($f->getReturnType() == "int") {
$tables[$f->getReturnType()][] = array(
"name" => "error",
"value" => "0",
);
}
if (preg_match("/git_oid/", $f->getReturnType())) {
$tables["char"][] = array(
"name" => "__result[GIT2_OID_HEXSIZE]",
"value" => "{0}",
);
}
if (preg_match("/_owner$/", $f->getName())) {
$tables["php_git2_t"][] = array(
"name" => "*__result",
"value" => "NULL",
);
}
if ($f->isCallbacker()) {
$tables["zend_fcall_info"][] = array(
"name" => "fci",
"value" => "empty_fcall_info",
);
$tables["zend_fcall_info_cache"][] = array(
"name" => "fcc",
"value" => "empty_fcall_info_cache",
);
$tables["php_git2_cb_t"][] = array(
"name" => "*cb",
"value" => "NULL",
);
}
foreach ($tables as $type => $values) {
$printer->put("`type` ", "type", $type);
$i = 0;
$cnt = count($values);
foreach ($values as $val) {
$printer->put("`name` = `value`", "name", $val['name'], "value", $val["value"]);
if ($i+1 < $cnt) {
$printer->put(", ");
}
$i++;
}
$printer->put(";\n");
}
}
public function generateParse(Printer $printer, Func $f)
{
$printer->put("if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\n");
$printer->block(function(Printer $printer) use ($f) {
$i = 0;
$cnt = count($f->getArguments());
$printer->put('"');
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($i == 0 && $f->isResourceCreator()) {
$i++;
continue;
}
if ($arg->shouldWrite()) {
$i++;
continue;
}
if (preg_match("/char/", $arg->getZendType())) {
$printer->put("s");
} else if (preg_match("/long/", $arg->getZendType())) {
$printer->put("l");
} else if (preg_match("/git_signature/", $arg->getType())) {
$printer->put("a");
} else if (preg_match("/git_strarray/", $arg->getType())) {
$printer->put("a");
} else if ($this->shouldResource($arg)) {
$printer->put("r");
} else if ($arg->isCallback()) {
$printer->put("f");
} else if ($f->isCallbacker() && preg_match("/payload/", $arg->getName())) {
$printer->put("z");
} else {
$printer->put("<{$arg->getType()}>");
}
}
$printer->put('", ');
$i = 0;
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($i == 0 && $f->isResourceCreator()) {
$i++;
continue;
}
if ($arg->shouldWrite()) {
$i++;
continue;
}
if ($arg->isCallback()) {
$printer->put("&fci, ");
$printer->put("&fcc");
} else {
$printer->put("&`name`", "name", $arg->getName());
}
if (preg_match("/char/", $arg->getZendType())) {
$printer->put(", ");
$printer->put("&`name`_len", "name", $arg->getName());
}
if ($i+1 < $cnt) {
$printer->put(", ");
}
$i++;
}
$printer->put(") == FAILURE) {\n");
$printer->put("return;\n");
});
$printer->put("}\n");
}
public function generateFetchResourceIfNeeded(Printer $printer, Func $f)
{
$i = 0;
foreach ($f->getArguments() as $arg) {
if ($f->isResourceCreator() && $i == 0) {
$i++;
continue;
}
if ($this->shouldResource($arg) && !$arg->shouldWrite()) {
$printer->put("ZEND_FETCH_RESOURCE(_`container`, php_git2_t*, &`value`, -1, PHP_GIT2_RESOURCE_NAME, git2_resource_handle);\n",
"container", $arg->getName(),
"value", $arg->getName()
);
}
$i++;
}
}
public function generateOidTranslation(Printer $printer, Func $f)
{
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($arg->getType() == "git_oid") {
$printer->put("if (git_oid_fromstrn(&__`name`, `name`, `name`_len)) {\n",
"name", $arg->getName()
);
$printer->block(function(Printer $printer) use($arg) {
$printer->put("RETURN_FALSE;\n");
});
$printer->put("}\n");
$arg->setName("__" . $arg->getName());
}
}
}
public function generateCallbackInit(Printer $printer, Func $f)
{
if ($f->isCallbacker()) {
$printer->put("if (php_git2_cb_init(&cb, &fci, &fcc, payload TSRMLS_CC)) {\n");
$printer->block(function(Printer $printer) {
$printer->put("RETURN_FALSE;\n");
});
$printer->put("}\n");
}
}
public function generateCallbackFree(Printer $printer, Func $f)
{
if ($f->isCallbacker()) {
$printer->put("php_git2_cb_free(cb);\n");
}
}
public function generateFunctionCall(Printer $printer, Func $f)
{
$this->generateOidTranslation($printer, $f);
$this->generateCallbackInit($printer, $f);
if ($f->getReturnType() == "int" && $f->isResourceCreator()) {
$printer->put("error = `function`",
"function", $f->getName()
);
$printer->put("(");
$i = 0;
$cnt = count($f->getArguments());
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($i == 0 && $f->isResourceCreator()) {
$printer->put("&");
}
if ($i != 0) {
if ($this->shouldResource($arg) && !$arg->shouldWrite()) {
$printer->put("PHP_GIT2_V(_`name`, `type`)",
"name", $arg->getName(),
"type", $this->getNormarizedTypeName($arg)
);
} else if ($arg->shouldWrite()) {
$printer->put("&`name`", "name", $arg->getName());
} else {
$printer->put("`name`", "name", $arg->getName());
}
} else {
$printer->put("`name`", "name", $arg->getName());
}
if ($i + 1 < $cnt) {
$printer->put(", ");
}
$i++;
}
$printer->put(");");
$printer->put("\n");
} else if ($f->isResourceCreator()) {
$printer->put("`retval` = `function`",
"retval", "result",
"function", $f->getName()
);
$printer->put("(");
$i = 0;
$cnt = count($f->getArguments());
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($i == 0 && $f->isResourceCreator()) {
$printer->put("&");
}
if ($i != 0) {
if ($this->shouldResource($arg) && !$arg->shouldWrite()) {
$printer->put("PHP_GIT2_V(_`name`, `type`)",
"name", $arg->getName(),
"type", $this->getNormarizedTypeName($arg)
);
} else if ($arg->shouldWrite()) {
$printer->put("&`name`", "name", $arg->getName());
} else {
$printer->put("`name`", "name", $arg->getName());
}
} else {
$printer->put("`name`", "name", $arg->getName());
}
if ($i + 1 < $cnt) {
$printer->put(", ");
}
$i++;
}
$printer->put(");\n");
} else if ($f->isArrayCreator()) {
$printer->put("result = `function`",
"function", $f->getName()
);
$printer->put("(");
$i = 0;
$cnt = count($f->getArguments());
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($this->shouldResource($arg) && !$arg->shouldWrite()) {
$printer->put("PHP_GIT2_V(_`name`, `type`)",
"name", $arg->getName(),
"type", $this->getNormarizedTypeName($arg)
);
} else if ($arg->shouldWrite()) {
$printer->put("&`name`", "name", $arg->getName());
} else {
$printer->put("`name`", "name", $arg->getName());
}
if ($i + 1 < $cnt) {
$printer->put(", ");
}
$i++;
}
$printer->put(");\n");
if (preg_match("/git_oid/", $f->getReturnType())) {
$printer->put("git_oid_fmt(__result, `name`);\n", "name", "result");
$printer->put("RETURN_STRING(__result, 1);\n");
} else if (preg_match("/_owner$/", $f->getName())) {
$this->generateMakeResourceIfNeeded($printer, $f, "__result", 1);
} else if (preg_match("/_type/", $f->getName())) {
$printer->put("RETURN_LONG(`name`);\n", "name", "result");
} else if (preg_match("/git_signature/", $f->getReturnType())) {
$printer->put("php_git2_signature_to_array(result, &__result TSRMLS_CC);\n");
$printer->put("RETURN_ZVAL(__result, 0, 1);\n");
} else {
$printer->put("/* TODO(chobie): implement this */\n");
}
} else if ($f->isLongCreator()) {
$printer->put("result = `function`",
"function", $f->getName()
);
$printer->put("(");
$i = 0;
$cnt = count($f->getArguments());
foreach ($f->getArguments() as $arg) {
/** @var Arg $arg */
if ($this->shouldResource($arg) && !$arg->shouldWrite()) {
$printer->put("PHP_GIT2_V(_`name`, `type`)",
"name", $arg->getName(),
"type", $this->getNormarizedTypeName($arg)
);
} else if ($arg->shouldWrite()) {
$printer->put("&`name`", "name", $arg->getName());
} else if ($arg->isCallback()) {
$printer->put("