name = $name; $this->summary = $summary; $this->desc = empty($desc) ? "&warn.undocumented.func;" : $desc; $this->code = $code; $this->role = empty($role) ? "public" : $role; if ($this->role === "public") { $this->status = $this->parse_proto($proto); } } function parse_proto($proto) { // 'tokenize' it $len=strlen($proto); $name=""; $tokens=array(); for ($n=0;$n<$len;$n++) { $char = $proto{$n}; if (ereg("[a-zA-Z0-9_]",$char)) { $name.=$char; } else { if ($name) $tokens[]=$name; $name=""; if (trim($char)) $tokens[]=$char; } } if ($name) $tokens[]=$name; $n=0; $opts=0; $params=array(); $return_type = ($this->is_type($tokens[$n])) ? $tokens[$n++] : "void"; $function_name = $tokens[$n++]; if ($return_type === "resource" && $tokens[$n] !== "(") { $return_subtype = $function_name; $function_name = $tokens[$n++]; } if (! $this->is_name($function_name)) { return("$function_name is not a valid function name"); } if ($function_name != $this->name) { return "proto function name is '$function_name' instead of '{$this->name}'"; } if ($tokens[$n]!='(') return("'(' expected instead of '$tokens[$n]'"); if ($tokens[++$n]!=')') { for ($param=0;$tokens[$n];$n++,$param++) { if ($tokens[$n]=='[') { $params[$param]['optional']=true; $opts++; $n++; if ($param>0) { if ($tokens[$n]!=',') return("',' expected after '[' instead of '$token[$n]'"); $n++; } } if (!$this->is_type($tokens[$n])) return("type name expected instead of '$tokens[$n]'"); $params[$param]['type']=$tokens[$n]; $n++; if ($tokens[$n] == "&") { $params[$param]['by_ref'] = true; $n++; } if ($this->is_name($tokens[$n])) { $params[$param]['name']=$tokens[$n]; $n++; } if ($tokens[$n] == "&") { $params[$param]['by_ref'] = true; $n++; } if ($params[$param]['type'] === "resource" && $this->is_name($tokens[$n])) { $params[$param]['subtype'] = $params[$param]['name']; $params[$param]['name'] = $tokens[$n]; $n++; } if ($tokens[$n]=='[') { $n--; continue; } if ($tokens[$n]==',') continue; if ($tokens[$n]==']') break; if ($tokens[$n]==')') break; } } $numopts=$opts; while ($tokens[$n]==']') { $n++; $opts--; } if ($opts!=0) return ("'[' / ']' count mismatch"); if ($tokens[$n] != ')') return("')' expected instead of '$tokens[$n]'"); $this->name = $function_name; $this->returns = $return_type; if (isset($return_subtype)) { $this->returns .= " $return_subtype"; } $this->params = $params; $this->optional = $numopts; return true; } function c_code($extension) { $code = ""; $returns = explode(" ", $this->returns); switch ($this->role) { case "public": $code .= "\n/* {{{ proto {$this->returns} {$this->name}("; if (isset($this->params)) { foreach ($this->params as $key => $param) { if (!empty($param['optional'])) $code.=" ["; if ($key) $code.=", "; $code .= $param['type']." "; if (isset($param['subtype'])) { $code .= $param['subtype']." "; } if ($param['type'] !== 'void') { if (isset($param['by_ref'])) { $code .= "&"; } $code .= $param['name']; } } } for ($n=$this->optional; $n>0; $n--) { $code .= "]"; } $code .= ")\n "; if (!empty($this->summary)) { $code .= $this->summary; } $code .= " */\n"; $code .= "PHP_FUNCTION({$this->name})\n"; $code .= "{\n"; if ($returns[0] === "resource" && isset($returns[1])) { $resource = $extension->resources[$returns[1]]; if ($resource->alloc === "yes") { $payload = $resource->payload; $code .= " $payload * return_res = ($payload *)emalloc(sizeof($payload));\n"; } } if (isset($this->params) && count($this->params)) { $arg_string=""; $arg_pointers=array(); $optional=false; $res_fetch=""; foreach ($this->params as $key => $param) { if ($param["type"] === "void") continue; $name = $param['name']; $arg_pointers[]="&$name"; if (isset($param['optional'])&&!$optional) { $optional=true; $arg_string.="|"; } switch ($param['type']) { case "bool": $arg_string.="b"; $code .= " zend_bool $name = 0;\n"; break; case "int": $arg_string.="l"; $code .= " long $name = 0;\n"; break; case "float": $arg_string.="d"; $code .= " double $name = 0.0;\n"; break; case "string": $arg_string.="s"; $code .= " char * $name = NULL;\n"; $code .= " int {$name}_len = 0;\n"; $arg_pointers[]="&{$name}_len"; break; case "array": $arg_string.="a"; $code .= " zval * $name = NULL;\n"; break; case "object": $arg_string.="o"; $code .= " zval * $name = NULL;\n"; break; case "resource": $arg_string.="r"; $code .= " zval * $name = NULL;\n"; $code .= " int {$name}_id = -1;\n"; // dummfug? $arg_pointers[]="&{$name}_id"; if (isset($param['subtype'])) { $resource = $extension->resources[$param['subtype']]; $varname = "res_{$name}"; $code .= " {$resource->payload} * $varname;\n"; $res_fetch.=" if ($name) {\n" ." ZEND_FETCH_RESOURCE($varname, {$resource->payload} *, &$name, {$name}_id, \"$param[subtype]\", le_$param[subtype]);\n" ." }\n"; } else { $res_fetch.=" if ($name) {\n" ." ZEND_FETCH_RESOURCE(???, ???, $name, {$name}_id, \"???\", ???_rsrc_id);\n" ." }\n"; } break; case "stream": $arg_string .= "r"; $code .= " zval * _z$name = NULL; \n"; $code .= " php_stream * $name = NULL:\n"; $res_fetch.= " php_stream_from_zval($name, &_z$name);\n"; break; case "mixed": case "callback": $arg_string.="z"; $code .= " zval * $name = NULL;\n"; break; } } } if (isset($arg_string) && strlen($arg_string)) { $code .= " int argc = ZEND_NUM_ARGS();\n\n"; $code .= " if (zend_parse_parameters(argc TSRMLS_CC, \"$arg_string\", ".join(", ",$arg_pointers).") == FAILURE) return;\n"; if ($res_fetch) $code.="\n$res_fetch\n"; } else { $code .= " if (ZEND_NUM_ARGS()>0) { WRONG_PARAM_COUNT; }\n\n"; } if ($this->code) { $code .= " {\n$this->code }\n"; // {...} for local variables ... } else { $code .= " php_error(E_WARNING, \"{$this->name}: not yet implemented\"); RETURN_FALSE;\n\n"; switch ($returns[0]) { case "void": break; case "bool": $code .= " RETURN_FALSE;\n"; break; case "int": $code .= " RETURN_LONG(0);\n"; break; case "float": $code .= " RETURN_DOUBLE(0.0);\n"; break; case "string": $code .= " RETURN_STRINGL(\"\", 0, 1);\n"; break; case "array": $code .= " array_init(return_value);\n"; break; case "object": $code .= " object_init(return_value)\n"; break; case "resource": if (isset($returns[1])) { $code .= " ZEND_REGISTER_RESOURCE(return_value, return_res, le_$returns[1]);\n"; } else { $code .= " /* RETURN_RESOURCE(...); /*\n"; } break; case "stream": $code .= " /* php_stream_to_zval(stream, return_value); */\n"; break; case "mixed": $code .= " /* RETURN_...(...); /*\n"; break; default: $code .= " /* UNKNOWN RETURN TYPE '$this->returns' /*\n"; break; } } $code .= "}\n/* }}} */\n\n"; break; case "internal": if (!empty($this->code)) { $code .= " {\n"; $code .= $this->code."\n"; $code .= " }\n"; } break; case "private": $code .= $this->code."\n"; break; } return $code; } function docbook_xml() { $xml = ' name)).'"> '.$this->name.' '.$this->summary.' Description '; $xml .= " {$this->returns}{$this->name}\n"; if (empty($this->params) || $this->params[0]["type"]==="void") { $xml .= " \n"; } else { foreach ($this->params as $key => $param) { if (isset($param['optional'])) { $xml .= " "; } else { $xml .= " "; } $xml .= "$param[type]"; if (isset($param['by_ref'])) { $xml .= "&"; } $xml .= "$param[name]"; $xml .= "\n"; } } $desc = $this->desc; if (!strstr($this->desc,"")) { $desc = " \n$desc \n"; } $xml .= ' '.$desc.' '; $xml .= $this->docbook_editor_settings(4); return $xml; } function write_test($extension) { $fp = fopen("{$extension->name}/tests/{$this->name}.phpt", "w"); fputs($fp, "--TEST-- {$this->name}() function --SKIPIF-- name}')) print 'skip'; ?> --POST-- --GET-- --FILE-- name}() yet'; ?> --EXPECT-- no test case for {$this->name}() yet"); fclose($fp); } } ?>