PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/system/idl/base.php

http://github.com/facebook/hiphop-php
PHP | 1274 lines | 1125 code | 125 blank | 24 comment | 228 complexity | 23e0b6f95dd4751c5db13c2d51f16efb MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT, LGPL-2.0, Apache-2.0
  1. <?php
  2. ///////////////////////////////////////////////////////////////////////////////
  3. // types
  4. define('Boolean', 1);
  5. define('Int32', 4);
  6. define('Int64', 5);
  7. define('Double', 6);
  8. define('String', 7);
  9. define('Int64Vec', 8);
  10. define('StringVec', 9);
  11. define('VariantVec', 10);
  12. define('Int64Map', 11);
  13. define('StringMap', 12);
  14. define('VariantMap', 13);
  15. define('Object', 14);
  16. define('Resource', 15);
  17. define('Variant', 16);
  18. define('Numeric', 17);
  19. define('Primitive', 18);
  20. define('PlusOperand', 19);
  21. define('Sequence', 20);
  22. define('Any', 21);
  23. define('TypeMask', 0x00FF);
  24. define('Reference', 0x0100);
  25. $TYPENAMES = array
  26. (Boolean => array('name' => 'bool', 'enum' => 'Boolean',
  27. 'idlname' => 'Boolean', 'phpname' => 'bool'),
  28. Int32 => array('name' => 'int', 'enum' => 'Int32',
  29. 'idlname' => 'Int32', 'phpname' => 'int'),
  30. Int64 => array('name' => 'int64_t', 'enum' => 'Int64',
  31. 'idlname' => 'Int64', 'phpname' => 'int'),
  32. Double => array('name' => 'double', 'enum' => 'Double',
  33. 'idlname' => 'Double', 'phpname' => 'float'),
  34. String => array('name' => 'String', 'enum' => 'String',
  35. 'idlname' => 'String', 'phpname' => 'string'),
  36. Int64Vec => array('name' => 'Array', 'enum' => 'Array',
  37. 'idlname' => 'Int64Vec', 'phpname' => 'vector'),
  38. StringVec => array('name' => 'Array', 'enum' => 'Array',
  39. 'idlname' => 'StringVec', 'phpname' => 'vector'),
  40. VariantVec => array('name' => 'Array', 'enum' => 'Array',
  41. 'idlname' => 'VariantVec', 'phpname' => 'vector'),
  42. Int64Map => array('name' => 'Array', 'enum' => 'Array',
  43. 'idlname' => 'Int64Map', 'phpname' => 'map'),
  44. StringMap => array('name' => 'Array', 'enum' => 'Array',
  45. 'idlname' => 'StringMap', 'phpname' => 'map'),
  46. VariantMap => array('name' => 'Array', 'enum' => 'Array',
  47. 'idlname' => 'VariantMap', 'phpname' => 'map'),
  48. Object => array('name' => 'Object', 'enum' => 'Object',
  49. 'idlname' => 'Object', 'phpname' => 'object'),
  50. Resource => array('name' => 'Resource', 'enum' => 'Resource',
  51. 'idlname' => 'Resource', 'phpname' => 'resource'),
  52. Variant => array('name' => 'Variant', 'enum' => 'Variant',
  53. 'idlname' => 'Variant', 'phpname' => 'mixed'),
  54. Numeric => array('name' => 'Numeric', 'enum' => 'Numeric',
  55. 'idlname' => 'Numeric', 'phpname' => 'number'),
  56. Primitive => array('name' => 'Primitive', 'enum' => 'Primitive',
  57. 'idlname' => 'Primitive', 'phpname' => 'num|string'),
  58. PlusOperand => array('name' => 'PlusOperand', 'enum' => 'PlusOperand',
  59. 'idlname' => 'PlusOperand','phpname' => 'num|array'),
  60. Sequence => array('name' => 'Sequence', 'enum' => 'Sequence',
  61. 'idlname' => 'Sequence', 'phpname' => 'string|array'),
  62. Any => array('name' => 'Variant', 'enum' => 'Some',
  63. 'idlname' => 'Any', 'phpname' => 'mixed'),
  64. );
  65. $REFNAMES = array('String' => 'CStrRef',
  66. 'Array' => 'CArrRef',
  67. 'Object' => 'CObjRef',
  68. 'Resource' => 'CResRef',
  69. 'Variant' => 'CVarRef',
  70. 'Numeric' => 'CVarRef',
  71. 'Primitive' => 'CVarRef',
  72. 'PlusOperand' => 'CVarRef',
  73. 'Sequence' => 'CVarRef',
  74. );
  75. $MAGIC_METHODS = array('__get' => 'ObjectData::UseGet',
  76. '__set' => 'ObjectData::UseSet',
  77. '__isset' => 'ObjectData::UseIsset',
  78. '__unset' => 'ObjectData::UseUnset',
  79. '__call' => 'ObjectData::HasCall',
  80. '__callStatic' => 'ObjectData::HasCallStatic');
  81. function get_idl_name($type, $null = '') {
  82. global $TYPENAMES;
  83. if ($type === null) {
  84. return $null;
  85. }
  86. if (is_string($type)) {
  87. return "'$type'";
  88. }
  89. if ($type & Reference) {
  90. return $TYPENAMES[$type & ~Reference]['idlname'] . ' | Reference';
  91. }
  92. return $TYPENAMES[$type]['idlname'];
  93. }
  94. function get_php_name($type, $null = 'mixed') {
  95. global $TYPENAMES;
  96. if ($type === null) {
  97. return $null;
  98. }
  99. if (is_string($type)) {
  100. return $type;
  101. }
  102. if ($type & Reference) {
  103. return $TYPENAMES[$type & ~Reference]['phpname'];
  104. }
  105. return $TYPENAMES[$type]['phpname'];
  106. }
  107. ///////////////////////////////////////////////////////////////////////////////
  108. // flags
  109. // ClassInfo attributes, and these numbers need to be consistent with them!
  110. define('ZendParamMode', 1 << 0);
  111. define('IsAbstract', 1 << 4);
  112. define('IsFinal', 1 << 5);
  113. define('IsPublic', 1 << 6);
  114. define('IsProtected', 1 << 7);
  115. define('IsPrivate', 1 << 8);
  116. define('AllowOverride', 1 << 8);
  117. define('IsStatic', 1 << 9);
  118. define('IsCppAbstract', 1 << 10);
  119. define('IsReference', 1 << 11);
  120. define('IsConstructor', 1 << 12);
  121. define('IsNothing', 1 << 13);
  122. define('ZendCompat', 1 << 14);
  123. define('IsCppSerializable', 1 << 15);
  124. define('HipHopSpecific', 1 << 16);
  125. define('VariableArguments', 1 << 17);
  126. define('RefVariableArguments', 1 << 18);
  127. define('MixedVariableArguments', 1 << 19);
  128. define('FunctionIsFoldable', 1 << 20);
  129. define('NoEffect', 1 << 21);
  130. define('NoInjection', 1 << 22);
  131. define('HasOptFunction', 1 << 23);
  132. define('AllowIntercept', 1 << 24);
  133. define('NoProfile', 1 << 25);
  134. define('ContextSensitive', 1 << 26);
  135. define('NoDefaultSweep', 1 << 27);
  136. define('IsSystem', 1 << 28);
  137. define('IsTrait', 1 << 29);
  138. define('NeedsActRec', 1 << 31);
  139. // Mask for checking the flags related to variable arguments
  140. define('VarArgsMask', (VariableArguments | RefVariableArguments |
  141. MixedVariableArguments));
  142. function get_flag_names($arr, $name, $global_func) {
  143. $flag = 0;
  144. if (!empty($arr[$name])) {
  145. $flag |= $arr[$name];
  146. }
  147. if ($flag == 0) return '';
  148. $ret = '';
  149. if ($flag & IsAbstract ) $ret .= ' | IsAbstract' ;
  150. if ($flag & IsFinal ) $ret .= ' | IsFinal' ;
  151. if ($flag & IsPublic ) $ret .= ' | IsPublic' ;
  152. if ($flag & IsProtected ) $ret .= ' | IsProtected' ;
  153. if ($global_func) {
  154. if ($flag & AllowOverride ) $ret .= ' | AllowOverride' ;
  155. } else {
  156. if ($flag & IsPrivate ) $ret .= ' | IsPrivate' ;
  157. }
  158. if ($flag & IsStatic ) $ret .= ' | IsStatic' ;
  159. if ($flag & HipHopSpecific ) $ret .= ' | HipHopSpecific' ;
  160. if ($flag & VariableArguments ) $ret .= ' | VariableArguments' ;
  161. if ($flag & RefVariableArguments ) $ret .= ' | RefVariableArguments' ;
  162. if ($flag & MixedVariableArguments) $ret .= ' | MixedVariableArguments';
  163. if ($flag & FunctionIsFoldable ) $ret .= ' | FunctionIsFoldable' ;
  164. if ($flag & NoEffect ) $ret .= ' | NoEffect' ;
  165. if ($flag & NoInjection ) $ret .= ' | NoInjection' ;
  166. if ($flag & HasOptFunction ) $ret .= ' | HasOptFunction' ;
  167. if ($flag & AllowIntercept ) $ret .= ' | AllowIntercept' ;
  168. if ($flag & NoProfile ) $ret .= ' | NoProfile' ;
  169. if ($flag & ContextSensitive ) $ret .= ' | ContextSensitive' ;
  170. if ($flag & NoDefaultSweep ) $ret .= ' | NoDefaultSweep' ;
  171. if ($flag & IsTrait ) $ret .= ' | IsTrait' ;
  172. if ($flag & NeedsActRec ) $ret .= ' | NeedsActRec' ;
  173. if ($ret == '') {
  174. throw new Exception("invalid flag $flag");
  175. }
  176. return substr($ret, 2);
  177. }
  178. function read_array_of_constant_names($flag_arr) {
  179. if (!is_array($flag_arr)) {
  180. return 0;
  181. }
  182. $flag = 0;
  183. foreach ($flag_arr as $constname) {
  184. $flag |= constant($constname);
  185. }
  186. return $flag;
  187. }
  188. ///////////////////////////////////////////////////////////////////////////////
  189. // schema functions that will be used (and only used) by schemas
  190. function ResetSchema() {
  191. global $current_class, $preamble, $funcs, $classes, $constants;
  192. $current_class = '';
  193. $preamble = '';
  194. $funcs = array();
  195. $classes = array();
  196. $constants = array();
  197. }
  198. ResetSchema();
  199. function BeginClass($class) {
  200. global $classes, $current_class;
  201. $current_class = $class['name'];
  202. if (!isset($class['parent'])) $class['parent'] = null;
  203. if (!isset($class['ifaces'])) $class['ifaces'] = array();
  204. if (!isset($class['bases'])) $class['bases'] = array();
  205. $class['methods'] = array();
  206. $class['properties'] = array();
  207. $class['consts'] = array();
  208. $class['flags'] = read_array_of_constant_names($class['flags']);
  209. $doc = get_class_doc_comments($class);
  210. if (!empty($doc)) {
  211. $class['doc'] = $doc;
  212. } else {
  213. $class['doc'] = null;
  214. }
  215. $classes[$current_class] = $class;
  216. }
  217. function EndClass() {
  218. global $classes, $current_class;
  219. $have_ctor = false;
  220. foreach ($classes[$current_class]['methods'] as $method) {
  221. if ($method['name'] == '__construct') $have_ctor = true;
  222. }
  223. // We don't have the information to autogenerate a ctor def,
  224. // so make the user do it.
  225. if (!$have_ctor) {
  226. throw new Exception("No constructor defined for class $current_class");
  227. }
  228. $current_class = '';
  229. }
  230. function idl_parse_type($t) {
  231. if (defined($t) && ($v = constant($t)) &&
  232. is_integer($v) && ($v > 0) && ($v < TypeMask)) {
  233. return $v;
  234. }
  235. error_log("Undefined type: $t", E_USER_WARNING);
  236. return $t;
  237. }
  238. function idl_infer_type($v) {
  239. switch(gettype($v)) {
  240. case 'boolean': return Boolean;
  241. case 'integer': return Int64;
  242. case 'double': return Double;
  243. case 'string': return String;
  244. case 'array': return VariantMap;
  245. case 'object': return Object;
  246. case 'resource': return Resource;
  247. default: return Any;
  248. }
  249. }
  250. function DefineConstant($const) {
  251. global $constants, $classes, $current_class;
  252. if (!isset($const['type']) && array_key_exists('value', $const)) {
  253. $const['type'] = idl_infer_type($const['value']);
  254. } else {
  255. $const['type'] = idl_parse_type($const['type']);
  256. }
  257. if (empty($current_class)) {
  258. $constants[] = $const;
  259. } else {
  260. $classes[$current_class]['consts'][] = $const;
  261. }
  262. }
  263. function DefineFunction($func) {
  264. global $classes, $current_class;
  265. if (empty($func['flags'])) {
  266. $func['flags'] = 0;
  267. } else {
  268. $func['flags'] = read_array_of_constant_names($func['flags']);
  269. if ($current_class && $classes[$current_class]['flags'] & HipHopSpecific) {
  270. $func['flags'] |= HipHopSpecific;
  271. }
  272. }
  273. if (!isset($func['return'])) $func['return'] = array();
  274. $func['ret_desc'] = idx($func['return'], 'desc');
  275. $func['ret_hint'] = idx($func['return'], 'hint');
  276. if (isset($func['return']['type'])) {
  277. if (idx($func['return'], 'ref')) {
  278. $func['return'] = Variant;
  279. } else {
  280. $func['return'] = idl_parse_type($func['return']['type']);
  281. }
  282. } else {
  283. $func['return'] = null;
  284. }
  285. $args = array();
  286. if (!empty($func['args'])) {
  287. foreach ($func['args'] as $arg) {
  288. if (array_key_exists('value', $arg)) {
  289. if (!is_string($arg['value']) || $arg['value'] === '') {
  290. throw new Exception('default value has to be non-empty string for '.
  291. $func['name'].'(..'.$arg['name'].'..)');
  292. }
  293. if (preg_match('/^q_([A-Za-z]+)_(\w+)$/', $arg['value'], $m)) {
  294. $class = $m[1];
  295. $constant = $m[2];
  296. $arg['default'] = "q_${class}_${constant}";
  297. } else {
  298. $arg['default'] = $arg['value'];
  299. }
  300. $arg['defaultSerialized'] = get_serialized_default($arg['value']);
  301. $arg['defaultText'] = get_default_text($arg['value']);
  302. }
  303. if (idx($arg, 'ref')) {
  304. $arg['type'] = Variant;
  305. } else {
  306. $arg['type'] = idl_parse_type($arg['type']);
  307. }
  308. $args[] = $arg;
  309. }
  310. $func['args'] = $args;
  311. } else {
  312. $func['args'] = array();
  313. }
  314. $doc = get_function_doc_comments($func, $current_class);
  315. if (!empty($doc)) {
  316. $func['doc'] = $doc;
  317. } else {
  318. $func['doc'] = null;
  319. }
  320. global $funcs, $classes, $current_class;
  321. if (empty($current_class)) {
  322. $funcs[] = $func;
  323. } else {
  324. $classes[$current_class]['methods'][] = $func;
  325. }
  326. }
  327. ///////////////////////////////////////////////////////////////////////////////
  328. // Read an IDL file into the 'funcs', 'classes' and 'consts' globals
  329. function ReadIDLFile($path) {
  330. $entries = json_decode(file_get_contents($path), /* use arrays */ true);
  331. if (!$entries) {
  332. throw new Exception("Unable to parse json from $path");
  333. }
  334. if (!empty($entries['funcs'])) {
  335. foreach ($entries['funcs'] as $func) {
  336. DefineFunction($func);
  337. }
  338. }
  339. if (!empty($entries['consts'])) {
  340. foreach ($entries['consts'] as $const) {
  341. DefineConstant($const);
  342. }
  343. }
  344. foreach ($entries['classes'] as $class) {
  345. $methods = isset($class['funcs']) ? $class['funcs'] : array();
  346. $consts = isset($class['consts']) ? $class['consts'] : array();
  347. unset($class['funcs']);
  348. unset($class['consts']);
  349. BeginClass($class);
  350. foreach ($methods as $method) {
  351. DefineFunction($method);
  352. }
  353. foreach ($consts as $const) {
  354. DefineConstant($const);
  355. }
  356. EndClass();
  357. }
  358. }
  359. ///////////////////////////////////////////////////////////////////////////////
  360. // code generation
  361. function typename($type, $prefix = true) {
  362. if (is_string($type)) {
  363. if ($prefix) return 'p_' . $type;
  364. return $type;
  365. }
  366. global $TYPENAMES;
  367. $type = $type & TypeMask;
  368. if ($type !== 0) {
  369. if (!isset($TYPENAMES[$type])) {
  370. exit("Unknown type $type\n");
  371. }
  372. return $TYPENAMES[$type]['name'];
  373. }
  374. return 'void';
  375. }
  376. function typeidlname($type, $null = '') {
  377. global $TYPENAMES;
  378. if ($type === null) {
  379. return $null;
  380. }
  381. if (is_string($type)) {
  382. return "'$type'";
  383. }
  384. if ($type & Reference) {
  385. return $TYPENAMES[$type & ~Reference]['idlname'];
  386. }
  387. return $TYPENAMES[$type]['idlname'];
  388. }
  389. function param_typename($arg, $forceRef = false) {
  390. $type = $arg['type'];
  391. if (is_string($type)) {
  392. return 'p_' . $type;
  393. }
  394. global $REFNAMES;
  395. $name = typename($type);
  396. $ref = idx($arg, 'ref');
  397. if (idx($arg, 'ref')) {
  398. return ($name === "Variant") ? "VRefParam" : $name;
  399. }
  400. if ($forceRef) {
  401. return $name;
  402. }
  403. return isset($REFNAMES[$name]) ? $REFNAMES[$name] : $name;
  404. }
  405. function typeenum($type) {
  406. if (is_string($type)) {
  407. return 'Void';
  408. }
  409. global $TYPENAMES;
  410. $type = $type & TypeMask;
  411. if ($type !== 0) {
  412. return $TYPENAMES[$type]['enum'];
  413. }
  414. return 'Void';
  415. }
  416. function fprintType($f, $type) {
  417. if (is_string($type)) {
  418. fprintf($f, 'S(999), "%s"', $type);
  419. } else {
  420. fprintf($f, 'T(%s)', typeenum($type));
  421. }
  422. }
  423. function get_serialized_default($s) {
  424. // These values are special and cannot be returned by
  425. // ReflectionParameter::getDefaultValue().
  426. if ($s == 'TimeStamp::Current()' ||
  427. preg_match('/^k_SQLITE3_/', $s)) {
  428. return "\x01";
  429. }
  430. if (preg_match('/^".*"$/', $s) ||
  431. preg_match('/^[\-0-9.]+$/', $s) ||
  432. preg_match('/^0x[0-9a-fA-F]+$/', $s) ||
  433. preg_match('/^(true|false|null)$/', $s)) {
  434. return serialize(eval("return $s;"));
  435. }
  436. if ($s == "empty_array") return serialize(array());
  437. if (preg_match('/^null_(string|array|object|resource|variant)$/', $s)) {
  438. return serialize(null);
  439. }
  440. if (preg_match('/^k_\w+( ?\| ?k_\w+)*$/', $s, $m)) {
  441. $s = preg_replace('/k_/', '', $s);
  442. return serialize(eval("return $s;"));
  443. }
  444. if (preg_match('/^q_([A-Za-z]+)\$\$(\w+)$/', $s, $m)) {
  445. $class = $m[1];
  446. $constant = $m[2];
  447. return serialize(eval("return $class::$constant;"));
  448. }
  449. if ($s == 'RAND_MAX') {
  450. return serialize(getrandmax());
  451. }
  452. if ($s == 'INT_MAX') {
  453. return serialize((1 << 31) - 1);
  454. }
  455. throw new Exception("Unable to serialize default value: [$s]");
  456. }
  457. function get_default_text($s) {
  458. if (preg_match('/^null_(string|array|object|variant)$/', $s)) {
  459. return 'null';
  460. }
  461. if (preg_match('/^k_\w+( ?\| ?k_\w+)*$/', $s, $m)) {
  462. return preg_replace('/k_/', '', $s);
  463. }
  464. if (preg_match('/^q_([A-Za-z]+)_(\w+)$/', $s, $m)) {
  465. $class = $m[1];
  466. $constant = $m[2];
  467. return "$class::$constant";
  468. }
  469. return $s;
  470. }
  471. function generateFuncCPPInclude($func, $f, $newline = true) {
  472. fprintf($f, '"%s", ', $func['name']);
  473. fprintType($f, $func['return']);
  474. fprintf($f, ', S(%d), ', idx($func, 'ref') ? 1 : 0);
  475. for ($i = 0; $i < count($func['args']); $i++) {
  476. $arg = $func['args'][$i];
  477. fprintf($f, '"%s", ', $arg['name']);
  478. fprintType($f, $arg['type']);
  479. fprintf($f, ', ');
  480. if (isset($arg['default'])) {
  481. $serialized = escape_cpp($arg['defaultSerialized']);
  482. fprintf($f, '"%s", S(%d), ',
  483. $serialized, strlen($arg['defaultSerialized']));
  484. fprintf($f, '"%s", ', escape_cpp($arg['defaultText']));
  485. } else {
  486. fprintf($f, 'NULL, S(0), NULL, ');
  487. }
  488. fprintf($f, 'S(%d), ', idx($arg, 'ref') ? 1 : 0);
  489. }
  490. fprintf($f, "NULL, ");
  491. fprintf($f, 'S(%d), ', $func['flags']);
  492. if (!empty($func['doc'])) {
  493. fprintf($f, '"%s", ', escape_cpp($func['doc']));
  494. }
  495. if (!empty($func['opt'])) {
  496. fprintf($f, 'S(%s), ', $func['opt']);
  497. }
  498. if ($newline) fprintf($f, "\n");
  499. }
  500. function generateFuncOptDecls($func, $f) {
  501. if ($func['opt']) {
  502. fprintf($f, "extern ExpressionPtr ".
  503. "%s(CodeGenerator *cg, AnalysisResultConstPtr ar, ".
  504. "SimpleFunctionCallPtr call, int mode);\n",
  505. $func['opt']);
  506. }
  507. }
  508. function generateConstCPPInclude($const, $f) {
  509. fprintf($f, '"%s", T(%s),'. "\n", $const['name'], typeenum($const['type']));
  510. }
  511. function generateClassCPPInclude($class, $f) {
  512. fprintf($f, '"%s", "%s", ', $class['name'], strtolower($class['parent']));
  513. foreach ($class['ifaces'] as $if) {
  514. fprintf($f, '"%s",', strtolower($if));
  515. }
  516. fprintf($f, 'NULL, ');
  517. foreach ($class['methods'] as $m) {
  518. generateMethodCPPInclude($m, $f);
  519. fprintf($f, ",");
  520. }
  521. fprintf($f, "NULL,");
  522. foreach ($class['properties'] as $p) {
  523. generatePropertyCPPInclude($p, $f);
  524. fprintf($f, ",");
  525. }
  526. fprintf($f, "NULL,");
  527. foreach ($class['consts'] as $k) {
  528. fprintf($f, '"%s", T(%s),', $k['name'], typeenum($k['type']));
  529. }
  530. fprintf($f, "NULL,\n");
  531. fprintf($f, 'S(%d), ', $class['flags']);
  532. if (!empty($class['doc'])) {
  533. fprintf($f, '"%s", ', escape_cpp($class['doc']));
  534. }
  535. }
  536. function generateMethodCPPInclude($method, $f) {
  537. generateFuncCPPInclude($method, $f, false, 'G');
  538. fprintf($f, "S(%d)", $method['flags']);
  539. }
  540. function generatePropertyCPPInclude($property, $f) {
  541. fprintf($f, "S(%d), \"%s\", ", $property['flags'], $property['name']);
  542. fprintType($f, $property['type']);
  543. }
  544. function generateFuncArgsCPPHeader($func, $f, $forceRef = false,
  545. $static = false) {
  546. $var_arg = ($func['flags'] & VarArgsMask);
  547. $args = $func['args'];
  548. fprintf($f, "(");
  549. if ($var_arg) fprintf($f, 'int _argc');
  550. if ($var_arg && count($args) > 0) fprintf($f, ', ');
  551. for ($i = 0; $i < count($args); $i++) {
  552. $arg = $args[$i];
  553. if ($i > 0) fprintf($f, ', ');
  554. fprintf($f, '%s %s', param_typename($arg, $forceRef),
  555. $arg['name']);
  556. if (isset($arg['default'])) {
  557. fprintf($f, ' = %s', $arg['default']);
  558. }
  559. }
  560. if ($var_arg) {
  561. fprintf($f, ', CArrRef _argv = null_array');
  562. }
  563. fprintf($f, ")");
  564. }
  565. function generateFuncArgsCall($func, $f) {
  566. $var_arg = ($func['flags'] & VarArgsMask);
  567. $args = $func['args'];
  568. if ($var_arg) fprintf($f, '_argc');
  569. if ($var_arg && count($args) > 0) fprintf($f, ', ');
  570. for ($i = 0; $i < count($args); $i++) {
  571. $arg = $args[$i];
  572. fprintf($f, ', ');
  573. fprintf($f, '%s', $arg['name']);
  574. }
  575. if ($var_arg) {
  576. fprintf($f, ', _argv');
  577. }
  578. }
  579. function generateFuncCPPForwardDeclarations($func, $f) {
  580. if (is_string($func['return'])) {
  581. fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n",
  582. typename($func['return'], false));
  583. }
  584. foreach ($func['args'] as $arg) {
  585. if (is_string($arg['type'])) {
  586. fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n",
  587. typename($arg['type'], false));
  588. }
  589. }
  590. }
  591. function generateFuncCPPHeader($func, $f, $method = false, $forceRef = false,
  592. $static = false, $class = false) {
  593. if ($method) {
  594. fprintf($f, '%s%s %s_%s', $static ? 'static ' : '',
  595. typename($func['return']), $static ? "ti" : "t",
  596. strtolower($func['name']));
  597. } else {
  598. generateFuncCPPForwardDeclarations($func, $f);
  599. fprintf($f, '%s f_%s', typename($func['return']), $func['name']);
  600. }
  601. generateFuncArgsCPPHeader($func, $f, $forceRef, $static);
  602. fprintf($f, ";\n");
  603. }
  604. function generateConstCPPHeader($const, $f) {
  605. $name = typename($const['type']);
  606. if ($name == 'String') {
  607. $name = 'StaticString';
  608. }
  609. fprintf($f, "extern const %s k_%s;\n", $name, $const['name']);
  610. }
  611. function generateConstCPPImplementation($const, $f, $prefix = 'k_') {
  612. $name = typename($const['type']);
  613. if ($name == 'String') {
  614. $name = 'StaticString';
  615. }
  616. $def = '';
  617. if (isset($const['value'])) {
  618. if ($name == 'StaticString') {
  619. $def = '"' . addslashes($const['value']) . '"';
  620. } else if ($name == 'bool') {
  621. $def = $const['value'] ? 'true' : 'false';
  622. } else {
  623. $def = $const['value'];
  624. }
  625. $def = " = $def";
  626. }
  627. fprintf($f, "const %s %s%s%s;\n", $name, $prefix, $const['name'], $def);
  628. }
  629. function generateClassCPPHeader($class, $f) {
  630. global $MAGIC_METHODS;
  631. $clsname = $class['name'];
  632. foreach ($class['consts'] as $k) {
  633. $name = typename($k['type']);
  634. if ($name == 'String') {
  635. $name = 'StaticString';
  636. }
  637. fprintf($f, "extern const %s q_%s\$\$%s;\n", $name, $clsname, $k['name']);
  638. }
  639. fprintf($f,
  640. <<<EOT
  641. ///////////////////////////////////////////////////////////////////////////////
  642. // class ${class['name']}
  643. EOT
  644. );
  645. fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n", $clsname);
  646. foreach ($class['properties'] as $p) {
  647. generatePropertyCPPForwardDeclarations($p, $f);
  648. }
  649. foreach ($class['methods'] as $m) {
  650. generateFuncCPPForwardDeclarations($m, $f);
  651. }
  652. fprintf($f, "class c_%s", $clsname);
  653. $flags = array();
  654. foreach ($class['methods'] as $m) {
  655. $name = $m['name'];
  656. if (isset($MAGIC_METHODS[$name]) && $MAGIC_METHODS[$name]) {
  657. $flags[$name] = $MAGIC_METHODS[$name];
  658. }
  659. }
  660. if ($class['parent']) {
  661. global $classes;
  662. $pclass = $class;
  663. while ($flags && $pclass['parent'] && isset($classes[$class['parent']])) {
  664. $pclass = $classes[$class['parent']];
  665. foreach ($pclass['methods'] as $m) {
  666. unset($flags[$m['name']]);
  667. }
  668. }
  669. fprintf($f, " : public c_" . $class['parent']);
  670. } else {
  671. fprintf($f, " : public ExtObjectData");
  672. if ($flags) {
  673. fprintf($f, "Flags<%s>", implode('|', $flags));
  674. $flags = false;
  675. }
  676. }
  677. foreach ($class['bases'] as $p) {
  678. fprintf($f, ", public $p");
  679. }
  680. $parents = array();
  681. fprintf($f, " {\n public:\n");
  682. fprintf($f, " DECLARE_CLASS(%s, %s, %s)\n", $clsname, $clsname,
  683. $class['parent'] ? $class['parent'] : 'ObjectData');
  684. fprintf($f, "\n");
  685. if (!empty($class['properties'])) {
  686. fprintf($f, " // properties\n");
  687. foreach ($class['properties'] as $p) {
  688. generatePropertyCPPHeader($p, $f);
  689. }
  690. fprintf($f, "\n");
  691. }
  692. fprintf($f, " // need to implement\n");
  693. if ($flags) {
  694. fprintf($f, " // constructor must call setAttributes(%s)\n",
  695. implode('|', $flags));
  696. }
  697. fprintf($f, " public: c_%s(Class* cls = c_%s::classof());\n",
  698. $class['name'], $class['name']);
  699. fprintf($f, " public: ~c_%s();\n", $class['name']);
  700. foreach ($class['methods'] as $m) {
  701. generateMethodCPPHeader($m, $class, $f);
  702. }
  703. fprintf($f, "\n");
  704. fprintf($f, " // implemented by HPHP\n");
  705. foreach ($class['methods'] as $m) {
  706. generatePreImplemented($m, $class, $f);
  707. }
  708. if (!empty($class['footer'])) {
  709. fprintf($f, $class['footer']);
  710. }
  711. fprintf($f, "\n};\n");
  712. }
  713. function generateClassCPPImplementation($class, $f) {
  714. foreach ($class['consts'] as $k) {
  715. generateConstCPPImplementation($k, $f, "q_{$class['name']}$$");
  716. }
  717. foreach ($class['methods'] as $m) {
  718. generateMethodCPPImplementation($m, $class, $f);
  719. }
  720. }
  721. function generateMethodCPPHeader($method, $class, $f) {
  722. global $MAGIC_METHODS;
  723. fprintf($f, " public: ");
  724. generateFuncCPPHeader($method, $f, true,
  725. isset($MAGIC_METHODS[$method['name']]),
  726. $method['flags'] & IsStatic, $class);
  727. }
  728. function generateMethodCPPImplementation($method, $class, $f) {
  729. if ($method['flags'] & IsStatic) {
  730. $prefix = "c_{$class['name']}::ti_";
  731. } else {
  732. $prefix = "c_{$class['name']}::t_";
  733. }
  734. generateFuncCPPImplementation($method, $f, $prefix);
  735. }
  736. function generatePropertyCPPHeader($property, $f) {
  737. fprintf($f, " public: ");
  738. fprintf($f, "%s m_%s;\n", typename($property['type']),
  739. $property['name']);
  740. }
  741. function generatePropertyCPPForwardDeclarations($property, $f) {
  742. if (is_string($property['type'])) {
  743. fprintf($f, "FORWARD_DECLARE_CLASS_BUILTIN(%s);\n",
  744. typename($property['type'], false));
  745. }
  746. }
  747. function generatePreImplemented($method, $class, $f) {
  748. if ($method['name'] == '__construct') {
  749. fprintf($f, " public: c_%s *create", $class['name']);
  750. generateFuncArgsCPPHeader($method, $f, true);
  751. fprintf($f, ";\n");
  752. }
  753. }
  754. function generateFuncCPPImplementation($func, $f, $prefix = 'f_') {
  755. $schema = "";
  756. $schema_no = 0;
  757. if ($func['return'] == Object || $func['return'] == Resource) {
  758. $schema .= '.set(' . ($schema_no++) . ', -1, "OO")';
  759. }
  760. $output = '';
  761. $need_ret = false;
  762. fprintf($f, '%s %s%s(',
  763. typename($func['return']),
  764. $prefix,
  765. strtolower($func['name']));
  766. $var_arg = ($func['flags'] & VarArgsMask);
  767. if ($var_arg) fprintf($f, 'int _argc');
  768. if ($var_arg && count($func['args']) > 0) fprintf($f, ', ');
  769. $params = "";
  770. $params_no = 0;
  771. for ($i = 0; $i < count($func['args']); $i++) {
  772. $arg = $func['args'][$i];
  773. if ($i > 0) fprintf($f, ', ');
  774. fprintf($f, '%s %s', param_typename($arg),
  775. $arg['name']);
  776. if (isset($arg['default'])) {
  777. fprintf($f, ' /* = %s */', $arg['default']);
  778. }
  779. if ($arg['type'] == Object || $arg['type'] == Resource) {
  780. $params .= '.set(' . ($params_no++) .
  781. ', (OpaqueObject::GetIndex(' . $arg['name'] . '))';
  782. } else {
  783. $params .= '.set(' . ($params_no++) . ', ' . $arg['name'] . ')';
  784. }
  785. if ($arg['type'] == Object || $arg['type'] == Resource) {
  786. if (idx($arg, 'ref')) {
  787. $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "OO")';
  788. } else {
  789. $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "O")';
  790. }
  791. } else if (idx($arg, 'ref')) {
  792. $schema .= '.set(' . ($schema_no++) . ', ' . $i . ', "R")';
  793. }
  794. if (idx($arg, 'ref')) {
  795. $need_ret = true;
  796. $output .= ' '.$arg['name'].' = ((Variant)_ret[1])['.$i.'];'."\n";
  797. }
  798. }
  799. if ($var_arg) {
  800. fprintf($f, ', CArrRef _argv /* = null_array */');
  801. }
  802. fprintf($f, ") {\n");
  803. fprintf($f, " throw NotImplementedException(__func__);\n");
  804. fprintf($f, "}\n\n");
  805. }
  806. function replaceParams($filename, $header) {
  807. global $funcs;
  808. $orig = $file = file_get_contents($filename);
  809. foreach ($funcs as &$func) {
  810. $var_arg = ($func['flags'] & VarArgsMask);
  811. $args = $func['args'];
  812. $search = '(?!return\s)\b\w+\s+f_'.$func['name'].'\s*\(\s*';
  813. if ($var_arg) $search .= '\w+\s+\w+';
  814. if ($var_arg && count($args) > 0) $search .= ',\s*';
  815. for ($i = 0; $i < count($args); $i++) {
  816. $arg = $args[$i];
  817. $search .= '\w+\s+\w+\s*';
  818. if (isset($arg['default'])) {
  819. if ($header) {
  820. $search .= '=\s*(?:'.preg_quote($arg['default'], '/').'|\d+)\s*';
  821. } else {
  822. $search .= '(?:\/\*\s*=\s*(?:'.preg_quote($arg['default'], '/').
  823. '|\d+)\s*\*\/\s*)?';
  824. }
  825. }
  826. if ($i < count($args) - 1) {
  827. $search .= ',(\s*)';
  828. }
  829. }
  830. if ($var_arg) {
  831. if ($header) {
  832. $search .= ',\s*\w+\s+\w+\s*=\s*null_array\s*';
  833. } else {
  834. $search .= ',(\s*)\w+\s+\w+\s*(?:\/\*\s*=\s*null_array\s*\*\/\s*)?';
  835. }
  836. }
  837. $search .= '\)';
  838. $replace = typename($func['return']).' f_'.$func['name'].'(';
  839. if ($var_arg) $replace .= 'int _argc, ';
  840. for ($i = 0; $i < count($args); $i++) {
  841. $arg = $args[$i];
  842. $replace .= param_typename($arg).' '.$arg['name'];
  843. if (isset($arg['default'])) {
  844. if ($header) {
  845. $replace .= ' = '.addcslashes($arg['default'], '\\');
  846. } else {
  847. $replace .= ' /* = '.addcslashes($arg['default'], '\\').' */';
  848. }
  849. }
  850. if ($i < count($args) - 1) {
  851. $replace .= ',${'.($i+1).'}';
  852. }
  853. }
  854. if ($var_arg) {
  855. if ($header) {
  856. $replace .= ', CArrRef _argv = null_array';
  857. } else {
  858. $replace .= ',${'.($i).'}';
  859. $replace .= 'CArrRef _argv /* = null_array */';
  860. }
  861. }
  862. $replace .= ')';
  863. if ($header && preg_match("/inline\s+$search/ms", $file)) {
  864. $func['inlined'] = true;
  865. }
  866. //var_dump($search, $replace);
  867. $count = preg_match_all("/$search/ms", $file, $m);
  868. if ($count == 0) {
  869. if ($header || !isset($func['inlined'])) {
  870. var_dump($search, $replace);
  871. print $func['name']." not found in $filename\n";
  872. }
  873. } else if ($count == 1) {
  874. $file = preg_replace("/$search/ms", $replace, $file);
  875. } else {
  876. print "skipped ".$func['name']." in $filename\n";
  877. }
  878. }
  879. if ($orig != $file) {
  880. file_put_contents($filename, $file);
  881. }
  882. }
  883. ///////////////////////////////////////////////////////////////////////////////
  884. // helpers
  885. function php_escape_val($val) {
  886. if (is_string($val)) {
  887. return '"'.escape_cpp($val).'"';
  888. } else if ($val === true) {
  889. return 'true';
  890. } else if ($val === false) {
  891. return 'false';
  892. } else if ($val === null) {
  893. return 'uninit_null()';
  894. } else {
  895. return var_export($val, true);
  896. }
  897. }
  898. function escape_php($val) {
  899. $val = preg_replace("/\\\\/", "\\\\\\\\", $val);
  900. $val = preg_replace("/\\\"/", "\\\\\"", $val);
  901. $val = preg_replace("/\\$/", "\\\\$", $val);
  902. $val = preg_replace("/\n/", "\\\\n", $val); // optional
  903. return $val;
  904. }
  905. function escape_cpp($val) {
  906. $len = strlen($val);
  907. $ret = '';
  908. for ($i = 0; $i < $len; $i++) {
  909. $ch = $val[$i];
  910. switch ($ch) {
  911. case "\n": $ret .= "\\n"; break;
  912. case "\r": $ret .= "\\r"; break;
  913. case "\t": $ret .= "\\t"; break;
  914. case "\a": $ret .= "\\a"; break;
  915. case "\b": $ret .= "\\b"; break;
  916. case "\f": $ret .= "\\f"; break;
  917. case "\v": $ret .= "\\v"; break;
  918. case "\0": $ret .= "\\000";break;
  919. case "\"": $ret .= "\\\""; break;
  920. case "\\": $ret .= "\\\\"; break;
  921. case "?": $ret .= "\\?"; break; // avoiding trigraph errors
  922. default:
  923. if (ord($ch) >= 0x20 && ord($ch) <= 0x7F) {
  924. $ret .= $ch;
  925. } else {
  926. $ret .= sprintf("\\%03o", ord($ch));
  927. }
  928. break;
  929. }
  930. }
  931. return $ret;
  932. }
  933. function idx($arr, $idx, $default=null) {
  934. if ($idx === null) {
  935. return $default;
  936. }
  937. if (isset($arr[$idx])) {
  938. return $arr[$idx];
  939. }
  940. return $default;
  941. }
  942. function format_doc_desc($arr, $clsname) {
  943. if (isset($arr['flags']) && $arr['flags'] & HipHopSpecific) {
  944. $desc = "( HipHop specific )\n";
  945. } else {
  946. $clsname = preg_replace('#_#', '-', strtolower($clsname));
  947. $name = preg_replace('#_#', '-', strtolower($arr['name']));
  948. $name = preg_replace('#^--#', '', $name);
  949. $url = "http://php.net/manual/en/$clsname.$name.php";
  950. $desc = "( excerpt from $url )\n";
  951. }
  952. $details = idx($arr, 'desc', '');
  953. if ($details) {
  954. $desc .= "\n$details";
  955. }
  956. return wordwrap($desc, 72)."\n\n";
  957. }
  958. function format_doc_arg($name, $type, $desc) {
  959. $width1 = 12;
  960. $width2 = 8;
  961. if (!$desc) $desc = ' ';
  962. $lines = explode("\n", wordwrap($desc, 72 - $width1 - $width2));
  963. $col = str_pad('@'.$name, $width1 - 1);
  964. $ret = $col;
  965. if (strlen($col) >= $width1) {
  966. $ret .= "\n".str_repeat(' ', $width1 - 1);
  967. }
  968. $col = str_pad(get_php_name($type), $width2 - 1);
  969. $ret .= ' '.$col;
  970. if (strlen($col) >= $width2) {
  971. $ret .= "\n".str_repeat(' ', $width1 + $width2 - 1);
  972. }
  973. $ret .= ' '.$lines[0]."\n";
  974. for ($i = 1; $i < count($lines); $i++) {
  975. $ret .= rtrim(str_repeat(' ', $width1 + $width2) . $lines[$i])."\n";
  976. }
  977. return $ret;
  978. }
  979. function format_doc_comment($text, $indent_spaces = 0) {
  980. $lines = explode("\n", $text);
  981. $indent = str_repeat(' ', $indent_spaces);
  982. $ret = "$indent/**\n";
  983. for ($i = 0; $i < count($lines) - 1; $i++) {
  984. $line = $lines[$i];
  985. $ret .= rtrim("$indent * $line")."\n";
  986. }
  987. $ret .= "$indent */";
  988. return $ret;
  989. }
  990. function get_function_doc_comments($func, $clsname) {
  991. $text = format_doc_desc($func, empty($clsname) ? 'function' : $clsname);
  992. if ($func['args']) {
  993. foreach ($func['args'] as $arg) {
  994. $desc = idx($arg, 'desc', '');
  995. if (idx($func, 'ref')) {
  996. $desc = '(output) ' . $desc;
  997. }
  998. $text .= format_doc_arg($arg['name'], idx($arg, 'type'), $desc);
  999. }
  1000. }
  1001. $ret = ($func['return'] !== null || !empty($func['ret_desc']));
  1002. if ($func['args'] && $ret) {
  1003. $text .= "\n";
  1004. }
  1005. if ($ret) {
  1006. $text .= format_doc_arg('return', $func['return'], $func['ret_desc']);
  1007. }
  1008. return format_doc_comment($text, empty($clsname) ? 0 : 2);
  1009. }
  1010. function get_class_doc_comments($class) {
  1011. return format_doc_comment(format_doc_desc($class, 'class'));
  1012. }
  1013. ///////////////////////////////////////////////////////////////////////////////
  1014. // phpnet
  1015. function phpnet_clean($text) {
  1016. $text = preg_replace('#<!--UdmComment.*?/UdmComment-->#s', '', $text);
  1017. $text = preg_replace('#<div class="example-contents">.*?</div>#s',
  1018. '<>', $text);
  1019. $text = preg_replace('#<p class="para">#', '<>', $text);
  1020. $text = preg_replace('#<strong class="note">Note</strong>:#', '', $text);
  1021. $text = preg_replace('#<.+?'.'>#', '', $text);
  1022. $text = preg_replace('#[ \t\n]+#s', ' ', $text);
  1023. $text = preg_replace('# ?<> ?#', "\n\n", $text);
  1024. $text = preg_replace('/&#039;/', "'", $text);
  1025. $text = trim(html_entity_decode($text));
  1026. $text = preg_replace('/[^\t\n -~]/', '', $text);
  1027. $text = preg_replace('/WarningThis/', 'Warning: This', $text);
  1028. return $text;
  1029. }
  1030. function phpnet_get_function_info($name, $clsname = 'function') {
  1031. $clsname = preg_replace('#_#', '-', strtolower($clsname));
  1032. $name = preg_replace('#__#', '', strtolower($name));
  1033. $name = preg_replace('#_#', '-', $name);
  1034. $doc = @file_get_contents("http://php.net/manual/en/$clsname.$name.php");
  1035. if ($doc === false) {
  1036. return array();
  1037. }
  1038. $ret = array();
  1039. if (preg_match('#<div class="refsect1 description"[^>]*>(.*?)'.
  1040. '<div class="refsect1 #s', $doc, $m)) {
  1041. $desc = $m[1];
  1042. if (preg_match('#<p class="para rdfs-comment">(.*)</div>#s', $desc, $m)) {
  1043. $ret['desc'] = phpnet_clean($m[1]);
  1044. }
  1045. }
  1046. if (preg_match('#<div class="refsect1 parameters"[^>]*>(.*?)'.
  1047. '<div class="refsect1 #s', $doc, $m)) {
  1048. $desc = $m[1];
  1049. if (preg_match_all('#<span class="term">\s*<em><code class="parameter">(.*?)</code>#s', $desc, $m)) {
  1050. foreach ($m[1] as $param) {
  1051. $ret['param_names'][] = phpnet_clean($param);
  1052. }
  1053. }
  1054. if (preg_match_all('#<dd>(.*?)</dd>#s', $desc, $m)) {
  1055. foreach ($m[1] as $param) {
  1056. $ret['params'][] = phpnet_clean($param);
  1057. }
  1058. }
  1059. $desc = preg_replace('#<h3.*</h3>#', '', $desc);
  1060. $desc = preg_replace('#<dl>.*</dl>#s', '', $desc);
  1061. $desc = phpnet_clean($desc);
  1062. if (!empty($desc)) {
  1063. $ret['desc'] .= "\n$desc";
  1064. }
  1065. }
  1066. if (preg_match('#<div class="refsect1 returnvalues"[^>]*>(.*?)'.
  1067. '(<div class="refsect1 |<div id="usernotes">)#s', $doc, $m)) {
  1068. $desc = $m[1];
  1069. $desc = preg_replace('#<h3.*</h3>#', '', $desc);
  1070. $ret['ret'] = phpnet_clean($desc);
  1071. }
  1072. return $ret;
  1073. }
  1074. function phpnet_get_class_info($name) {
  1075. $name = preg_replace('#_#', '-', strtolower($name));
  1076. $doc = @file_get_contents("http://php.net/manual/en/class.$name.php");
  1077. if ($doc === false) {
  1078. return array();
  1079. }
  1080. $ret = array(
  1081. 'desc' => '',
  1082. 'props' => array(),
  1083. 'funcs' => array()
  1084. );
  1085. if (preg_match('#<h2 class="title">Introduction</h2>(.*?)'.
  1086. '<div class="section"#s', $doc, $m)) {
  1087. $ret['desc'] = phpnet_clean($m[1]);
  1088. }
  1089. if (preg_match('#"modifier">extends</span>.*?class="classname">(.*?)#s', $doc, $m)) {
  1090. $ret['parent'] = phpnet_clean($m[1]);
  1091. }
  1092. if (preg_match_all('#<var class="varname">(.*?)</var>#s', $doc, $m)) {
  1093. foreach ($m[1] as $prop) {
  1094. $ret['props'][] = phpnet_clean($prop);
  1095. }
  1096. }
  1097. if (preg_match_all(
  1098. '#<a href="'.$name.'\..*?.php">'.$name.'::(.*?)</a>#si',
  1099. $doc, $m)) {
  1100. foreach ($m[1] as $prop) {
  1101. $ret['funcs'][] = phpnet_clean($prop);
  1102. }
  1103. }
  1104. return $ret;
  1105. }
  1106. function phpnet_get_class_desc($name) {
  1107. $name = preg_replace('#_#', '-', strtolower($name));
  1108. $doc = @file_get_contents("http://php.net/manual/en/class.$name.php");
  1109. if ($doc !== false &&
  1110. preg_match('#<h2 class="title">Introduction</h2>(.*?)'.
  1111. '<div class="section"#s', $doc, $m)) {
  1112. return phpnet_clean($m[1]);
  1113. }
  1114. return false;
  1115. }
  1116. function phpnet_get_extension_functions($name) {
  1117. $doc = @file_get_contents("http://www.php.net/manual/en/ref.$name.php");
  1118. if ($doc === false) {
  1119. return array();
  1120. }
  1121. preg_match_all('#<li><a href="function\..*?\.php">(.*?)</a>.*?</li>#',
  1122. $doc, $m);
  1123. return $m[1];
  1124. }
  1125. function phpnet_get_extension_constants($name) {
  1126. $doc = @file_get_contents("http://www.php.net/manual/en/$name.constants.php");
  1127. if ($doc === false) {
  1128. return array();
  1129. }
  1130. preg_match_all('#<code>(.*?)</code>#', $doc, $m);
  1131. return $m[1];
  1132. }
  1133. function phpnet_get_extension_classes($name) {
  1134. $doc = @file_get_contents("http://www.php.net/manual/en/book.$name.php");
  1135. if ($doc === false) {
  1136. return array();
  1137. }
  1138. preg_match_all('#<a href="class.[^"]*.php">(.*?)</a>#', $doc, $m);
  1139. return $m[1];
  1140. }