PageRenderTime 50ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/CodeGen/PECL/Extension.php

https://github.com/lucciano/CodeGen_PECL
PHP | 2629 lines | 1774 code | 360 blank | 495 comment | 119 complexity | 6ae65736bf0ee5370005c811716fa686 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * A class that generates PECL extension soure and documenation files
  4. *
  5. * PHP versions 5
  6. *
  7. * LICENSE: This source file is subject to version 3.0 of the PHP license
  8. * that is available through the world-wide-web at the following URI:
  9. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  10. * the PHP License and are unable to obtain it through the web, please
  11. * send a note to license@php.net so we can mail you a copy immediately.
  12. *
  13. * @category Tools and Utilities
  14. * @package CodeGen_PECL
  15. * @author Hartmut Holzgraefe <hartmut@php.net>
  16. * @copyright 2005-2008 Hartmut Holzgraefe
  17. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  18. * @version CVS: $Id: Extension.php,v 1.75 2007/04/16 09:28:03 hholzgra Exp $
  19. * @version CVS: $Id: Extension.php,v 1.75 2007/04/16 09:28:03 hholzgra Exp $
  20. * @link http://pear.php.net/package/CodeGen_PECL
  21. */
  22. /**
  23. * includes
  24. */
  25. require_once "System.php";
  26. require_once "CodeGen/Extension.php";
  27. require_once "CodeGen/PECL/Release.php";
  28. require_once "CodeGen/PECL/Element.php";
  29. require_once "CodeGen/PECL/Element/Constant.php";
  30. require_once "CodeGen/PECL/Element/Function.php";
  31. require_once "CodeGen/PECL/Element/Resource.php";
  32. require_once "CodeGen/PECL/Element/Ini.php";
  33. require_once "CodeGen/PECL/Element/Global.php";
  34. require_once "CodeGen/PECL/Element/Logo.php";
  35. require_once "CodeGen/PECL/Element/Test.php";
  36. require_once "CodeGen/PECL/Element/Class.php";
  37. require_once "CodeGen/PECL/Element/Interface.php";
  38. require_once "CodeGen/PECL/Element/Stream.php";
  39. require_once "CodeGen/PECL/Dependency/With.php";
  40. require_once "CodeGen/PECL/Dependency/Lib.php";
  41. require_once "CodeGen/PECL/Dependency/Header.php";
  42. require_once "CodeGen/PECL/Dependency/Extension.php";
  43. require_once "CodeGen/PECL/Dependency/Platform.php";
  44. /**
  45. * A class that generates PECL extension soure and documenation files
  46. *
  47. * @category Tools and Utilities
  48. * @package CodeGen_PECL
  49. * @author Hartmut Holzgraefe <hartmut@php.net>
  50. * @copyright 2005-2008 Hartmut Holzgraefe
  51. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  52. * @version Release: 1.1.3
  53. * @link http://pear.php.net/package/CodeGen_PECL
  54. */
  55. class CodeGen_PECL_Extension
  56. extends CodeGen_Extension
  57. {
  58. /**
  59. * Current CodeGen_PECL version number
  60. *
  61. * @return string
  62. */
  63. function version()
  64. {
  65. return "1.1.3";
  66. }
  67. /**
  68. * CodeGen_PECL Copyright message
  69. *
  70. * @return string
  71. */
  72. function copyright()
  73. {
  74. return "Copyright (c) 2003-2006 Hartmut Holzgraefe";
  75. }
  76. // {{{ member variables
  77. /**
  78. * The public PHP functions defined by this extension
  79. *
  80. * @var array
  81. */
  82. protected $functions = array();
  83. /**
  84. * The extensions internal functions like MINIT
  85. *
  86. * @var array
  87. */
  88. protected $internalFunctions = array();
  89. /**
  90. * The constants defined by this extension
  91. *
  92. * @var array
  93. */
  94. protected $constants = array();
  95. /**
  96. * The PHP classes defined by this extension
  97. *
  98. * @var array
  99. */
  100. protected $classes = array();
  101. /**
  102. * The PHP interfaces defined by this extension
  103. *
  104. * @var array
  105. */
  106. protected $interfaces = array();
  107. /**
  108. * The extensions php.ini parameters
  109. *
  110. * @var array
  111. */
  112. protected $phpini = array();
  113. /**
  114. * The extensions internal global variables
  115. *
  116. * @var array
  117. */
  118. protected $globals = array();
  119. /**
  120. * The PHP resources defined by this extension
  121. *
  122. * @var array
  123. */
  124. protected $resources = array();
  125. /**
  126. * Custom test cases
  127. *
  128. * @var array
  129. */
  130. protected $testcases = array();
  131. /**
  132. * phpinfo logos
  133. *
  134. * @var string
  135. * @access private
  136. */
  137. protected $logos = array();
  138. /**
  139. * cross extension dependencies
  140. *
  141. * @var array
  142. */
  143. protected $otherExtensions = array();
  144. /**
  145. * generate #line specs?
  146. *
  147. * @var bool
  148. * @access private
  149. */
  150. protected $linespecs = false;
  151. /**
  152. * PHP Streams
  153. *
  154. * @var array
  155. * @access private
  156. */
  157. protected $streams = array();
  158. /**
  159. * --with configure options
  160. *
  161. * @var array
  162. * @access private
  163. */
  164. protected $with = array();
  165. /**
  166. * pear installer channel name
  167. *
  168. * @var string
  169. * @access private
  170. */
  171. protected $channel = "pecl.php.net";
  172. /**
  173. * phpdoc reference purpose
  174. *
  175. * See http://doc.php.net/php/en/dochowto/x1257.php for details
  176. *
  177. * @var string
  178. * @access private
  179. */
  180. protected $docPurpose = "utilspec";
  181. // }}}
  182. // {{{ constructor
  183. /**
  184. * The constructor
  185. *
  186. * @access public
  187. */
  188. function __construct()
  189. {
  190. $this->release = new CodeGen_PECL_Release;
  191. $this->platform = new CodeGen_PECL_Dependency_Platform("all");
  192. parent::__construct();
  193. }
  194. // }}}
  195. // {{{ member adding functions
  196. /**
  197. * Add a function to the extension
  198. *
  199. * @access public
  200. * @param object a function object
  201. */
  202. function addFunction(CodeGen_PECL_Element_Function $function)
  203. {
  204. $name = $function->getName();
  205. $role = $function->getRole();
  206. switch ($role) {
  207. case "public":
  208. if (isset($this->functions[$name])) {
  209. return PEAR::raiseError("public function '$name' has been defined before");
  210. }
  211. $this->functions[$name] = $function;
  212. return true;
  213. case "private":
  214. return PEAR::raiseError("private functions are no longer supported, use <code> sections instead");
  215. case "internal":
  216. if (isset($this->internalFunctions[$name])) {
  217. return PEAR::raiseError("internal '$name' has been defined before");
  218. }
  219. $this->internalFunctions[$name] = $function;
  220. return true;
  221. default:
  222. return PEAR::raiseError("unnokwn function role '$role'");
  223. }
  224. }
  225. /**
  226. * Set target platform for generated code
  227. *
  228. * @access public
  229. * @param string platform name
  230. */
  231. function setPlatform($type)
  232. {
  233. $this->platform = new CodeGen_PECL_Dependency_Platform($type);
  234. if (PEAR::isError($this->platform)) {
  235. return $this->platform;
  236. }
  237. return true;
  238. }
  239. /**
  240. * Add a PHP constant to the extension
  241. *
  242. * @access public
  243. * @param object a constant object
  244. */
  245. function addConstant(CodeGen_PECL_Element_Constant $constant)
  246. {
  247. $name = $constant->getName();
  248. if (isset($this->constants[$name])) {
  249. return PEAR::raiseError("constant '$name' has been defined before");
  250. }
  251. $this->constants[$name] = $constant;
  252. return true;
  253. }
  254. /**
  255. * Add a PHP ini directive
  256. *
  257. * @access public
  258. * @param object a phpini object
  259. */
  260. function addPhpIni(CodeGen_PECL_Element_Ini $phpini)
  261. {
  262. $name = $phpini->getName();
  263. if (isset($this->phpini[$name])) {
  264. return PEAR::raiseError("php.ini directive '$name' has been defined before");
  265. }
  266. $this->phpini[$name] = $phpini;
  267. return true;
  268. }
  269. /**
  270. * Add a internal global variable
  271. *
  272. * @access public
  273. * @param object a global object
  274. */
  275. function addGlobal(CodeGen_PECL_Element_Global $global)
  276. {
  277. $name = $global->getName();
  278. if (isset($this->globals[$name])) {
  279. return PEAR::raiseError("global '{$name}' has been defined before");
  280. }
  281. $this->globals[$name] = $global;
  282. return true;
  283. }
  284. /**
  285. * Add a PHP resource type
  286. *
  287. * @access public
  288. * @param object a resource object
  289. */
  290. function addResource(CodeGen_PECL_Element_Resource $resource)
  291. {
  292. $name = $resource->getName();
  293. if (isset($this->resources[$name])) {
  294. return PEAR::raiseError("resource type '{$name}' has been defined before");
  295. }
  296. $this->resources[$name] = $resource;
  297. return true;
  298. }
  299. /**
  300. * Get PHP resource types
  301. *
  302. * @access public
  303. * @return array
  304. */
  305. function getResources()
  306. {
  307. return $this->resources;
  308. }
  309. /**
  310. * Get a specific resource by name
  311. *
  312. * @access public
  313. * @param string resource name
  314. * @return object resource object or false if not found
  315. */
  316. function getResource($name)
  317. {
  318. if (isset($this->resources[$name])) {
  319. return $this->resources[$name];
  320. }
  321. return false;
  322. }
  323. /**
  324. * Get PHP constants
  325. *
  326. * @access public
  327. * @return array
  328. */
  329. function getConstants()
  330. {
  331. return $this->constants;
  332. }
  333. /**
  334. * Get a specific constant by name
  335. *
  336. * @access public
  337. * @param string constant name
  338. * @return object constant object or false if not found
  339. */
  340. function getConstant($name)
  341. {
  342. if (isset($this->constants[$name])) {
  343. return $this->constants[$name];
  344. }
  345. return false;
  346. }
  347. /**
  348. * Get a specific class by name
  349. *
  350. * @access public
  351. * @param string class name
  352. * @return object class object or false if not found
  353. */
  354. function getClass($name)
  355. {
  356. if (isset($this->classes[$name])) {
  357. return $this->classes[$name];
  358. }
  359. return false;
  360. }
  361. /**
  362. * Add a PHP class to the extension
  363. *
  364. * @access public
  365. * @param object a class object
  366. */
  367. function addClass(CodeGen_PECL_Element_Class $class)
  368. {
  369. if (isset($this->classes[$class->getName()])) {
  370. return PEAR::raiseError("class '".$class->getName()."' has been defined before");
  371. }
  372. $this->classes[$class->getName()] = $class;
  373. return true;
  374. }
  375. /**
  376. * Add a PHP interface to the extension
  377. *
  378. * @access public
  379. * @param object an interface object
  380. */
  381. function addInterface(CodeGen_PECL_Element_Interface $interface)
  382. {
  383. if (isset($this->interfaces[$interface->getName()])) {
  384. return PEAR::raiseError("interface '".$interface->getName()."' has been defined before");
  385. }
  386. $this->interfaces[$interface->getName()] = $interface;
  387. return true;
  388. }
  389. /**
  390. * Add a PHP stream wrapper to the extension
  391. *
  392. * @access public
  393. * @param object a stream wrapper object
  394. */
  395. function addStream(CodeGen_PECL_Element_Stream $stream)
  396. {
  397. if (isset($this->streams[$stream->getName()])) {
  398. return PEAR::raiseError("stream '".$stream->getName()."' has been defined before");
  399. }
  400. $this->streams[$stream->getName()] = $stream;
  401. return true;
  402. }
  403. /**
  404. * Add a --with configure option
  405. *
  406. * @access public
  407. * @param object 'With' object
  408. * @returns bool
  409. */
  410. function addWith(CodeGen_PECL_Dependency_With $with)
  411. {
  412. $name = $with->getName();
  413. if (isset($this->with[$name])) {
  414. return PEAR::raiseError("--with-{$name} declared twice");
  415. }
  416. $this->with[$name] = $with;
  417. return true;
  418. }
  419. /**
  420. * Add phpinfo logo
  421. *
  422. * @access public
  423. * @param object the logo
  424. */
  425. function addLogo(CodeGen_PECL_Element_Logo $logo)
  426. {
  427. $name = $logo->getName();
  428. if (isset($this->logos[$name])) {
  429. return PEAR::raiseError("logo '{$name}' already defined");
  430. }
  431. $this->logos[$name] = $logo;
  432. return true;
  433. }
  434. /**
  435. * Add cross-module dependency
  436. *
  437. * @param object extension dependency object
  438. */
  439. function addOtherExtension(CodeGen_PECL_Dependency_Extension $ext)
  440. {
  441. $name = $ext->getName();
  442. if (isset($this->otherExtensions[$name])) {
  443. return PEAR::raiseError("dependency to extension '{$name}' already defined");
  444. }
  445. $this->otherExtensions[$name] = $ext;
  446. return true;
  447. }
  448. /**
  449. * Generate #line specs?
  450. *
  451. * @access public
  452. * @param bool
  453. */
  454. function setLinespecs($state)
  455. {
  456. $this->linespecs = $state;
  457. }
  458. /**
  459. * linespec getter
  460. *
  461. * @access public
  462. * @return bool
  463. */
  464. function getLinespecs()
  465. {
  466. return $this->linespecs;
  467. }
  468. // }}}
  469. // {{{ output generation
  470. /**
  471. * Create the extensions including
  472. *
  473. * @access public
  474. * @param string Directory to create (default is ./$this->name)
  475. */
  476. function createExtension($dirpath = false, $force = false)
  477. {
  478. // default: create dir in current working directory,
  479. // dirname is the extensions base name
  480. if (!is_string($dirpath) || $dirpath == "") {
  481. $dirpath = "./" . $this->name;
  482. }
  483. // purge and create extension directory
  484. if ($dirpath !== ".") {
  485. if (!$force && file_exists($dirpath)) {
  486. return PEAR::raiseError("'$dirpath' already exists, can't create that directory (use '--force' to override)");
  487. } else if (!@System::mkdir("-p $dirpath")) {
  488. return PEAR::raiseError("can't create '$dirpath'");
  489. }
  490. }
  491. // make path absolute to be independant of working directory changes
  492. $this->dirpath = realpath($dirpath);
  493. // add "unknown" author if no authors specified
  494. if (empty($this->authors)) {
  495. $author = new CodeGen_PECL_Maintainer;
  496. $author->setUser("unknown");
  497. $author->setName("Unknown User");
  498. $author->setEmail("unknown@example.com");
  499. $author->setRole("lead");
  500. $this->addAuthor($author);
  501. }
  502. if (empty($this->description)) {
  503. $this->description = "none";
  504. }
  505. echo "Creating '{$this->name}' extension in '$dirpath'\n";
  506. // generate complete source code
  507. $this->generateSource();
  508. // copy additional source files
  509. if (isset($this->packageFiles['copy'])) {
  510. foreach ($this->packageFiles['copy'] as $targetpath => $sourcepath) {
  511. $targetpath = $this->dirpath."/".$targetpath;
  512. if (!is_dir(dirname($targetpath))) {
  513. mkdir(dirname($targetpath), 0777, true);
  514. }
  515. copy($sourcepath, $targetpath);
  516. }
  517. }
  518. // generate README file
  519. $this->writeReadme();
  520. // generate DocBook XML documantation for PHP manual
  521. $manpath = $this->dirpath . "/manual/";
  522. if (!@System::mkdir("-p $manpath")) {
  523. return PEAR::raiseError("can't create '$manpath'", E_USER_ERROR);
  524. }
  525. $this->generateDocumentation($manpath);
  526. }
  527. /**
  528. * Create the extensions code soure and project files
  529. *
  530. * @access public
  531. */
  532. function generateSource()
  533. {
  534. // generate source and header files
  535. $this->writeHeaderFile();
  536. $this->writeCodeFile();
  537. foreach ($this->logos as $logo) {
  538. $fp = new CodeGen_Tools_FileReplacer("{$this->dirpath}/".$logo->getName()."_logos.h");
  539. $fp->puts($logo->hCode());
  540. $fp->close();
  541. }
  542. // generate project files for configure (unices and similar platforms like cygwin)
  543. if ($this->platform->test("unix")) {
  544. $this->writeConfigM4();
  545. }
  546. // generate project files for Windows platform (VisualStudio/C++ V6)
  547. if ($this->platform->test("windows")) {
  548. $this->writeMsDevStudioDsp();
  549. $this->writeConfigW32();
  550. }
  551. // generate .cvsignore file entries
  552. $this->writeDotCvsignore();
  553. // generate EXPERIMENTAL file for unstable release states
  554. $this->writeExperimental();
  555. // generate CREDITS file
  556. $this->writeCredits();
  557. // generate LICENSE file if license given
  558. if ($this->license) {
  559. $this->license->writeToFile($this->dirpath."/LICENSE");
  560. $this->files['doc'][] = "LICENSE";
  561. }
  562. // generate test case templates
  563. $this->writeTestFiles();
  564. // generate PEAR/PECL package.xml file
  565. $this->writePackageXml();
  566. $this->writePackageXml2();
  567. }
  568. // {{{ docbook documentation
  569. /**
  570. * Create the extension documentation DocBook XML files
  571. *
  572. * @access public
  573. * @param string Directory to write to
  574. */
  575. function generateDocumentation($docdir)
  576. {
  577. $idName = str_replace('_', '-', $this->name);
  578. if (!@System::mkdir("-p $docdir/$idName")) {
  579. return PEAR::raiseError("can't create '$docdir/$idName'", E_USER_ERROR);
  580. }
  581. $manual = new CodeGen_Tools_FileReplacer("$docdir/manual.xml.in");
  582. $manual->puts("<?xml version='1.0' encoding='UTF-8' ?>
  583. <!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML V4.1.2//EN'
  584. '@PHPDOC@/dtds/dbxml-4.1.2/docbookx.dtd' [
  585. <!-- Add translated specific definitions and snippets -->
  586. <!ENTITY % language-defs SYSTEM '@PHPDOC@/en/language-defs.ent'>
  587. <!ENTITY % language-snippets SYSTEM '@PHPDOC@/en/language-snippets.ent'>
  588. %language-defs;
  589. %language-snippets;
  590. <!-- Fallback to English definitions and snippets (in case of missing translation) -->
  591. <!ENTITY % language-defs.default SYSTEM '@PHPDOC@/en/language-defs.ent'>
  592. <!ENTITY % language-snippets.default SYSTEM '@PHPDOC@/en/language-snippets.ent'>
  593. <!ENTITY % extensions.default SYSTEM '@PHPDOC@/en/extensions.ent'>
  594. %language-defs.default;
  595. %language-snippets.default;
  596. %extensions.default;
  597. <!-- All global entities for the XML files -->
  598. <!ENTITY % global.entities SYSTEM '@PHPDOC@/entities/global.ent'>
  599. <!ENTITY % file.entities SYSTEM './file-entities.ent'>
  600. <!-- Include all external DTD parts defined previously -->
  601. %global.entities;
  602. %file.entities;
  603. <!-- Autogenerated missing entites and IDs to make build work -->
  604. <!ENTITY % missing-entities SYSTEM '@PHPDOC@/entities/missing-entities.ent'>
  605. %missing-entities;
  606. ]>
  607. <book id='manual' lang='en'>
  608. &reference.$idName.reference;
  609. </book>
  610. ");
  611. $manual->close();
  612. $makefile = new CodeGen_Tools_FileReplacer("$docdir/Makefile");
  613. $makefile->puts("#
  614. all: html
  615. confcheck:
  616. \t@if test \"x$(PHPDOC)\" = \"x\"; then echo PHPDOC not set; exit 3; fi
  617. manual.xml: manual.xml.in
  618. \tsed -e's:@PHPDOC@:\$(PHPDOC):g' < manual.xml.in > manual.xml
  619. html: confcheck manual.xml
  620. \trm -rf html; mkdir html
  621. \tSP_ENCODING=XML SP_CHARSET_FIXED=YES openjade -D $(PHPDOC) -wno-idref -c $(PHPDOC)/docbook/docbook-dsssl/catalog -c $(PHPDOC)/phpbook/phpbook-dsssl/defaults/catalog -d $(PHPDOC)/phpbook/phpbook-dsssl/html.dsl -V use-output-dir -t sgml $(PHPDOC)/phpbook/phpbook-xml/phpdocxml.dcl manual.xml
  622. bightml: confcheck manual.xml
  623. \trm -rf html; mkdir html
  624. \tSP_ENCODING=XML SP_CHARSET_FIXED=YES openjade -D $(PHPDOC) -wno-idref -c $(PHPDOC)/docbook/docbook-dsssl/catalog -c $(PHPDOC)/phpbook/phpbook-dsssl/defaults/catalog -d $(PHPDOC)/phpbook/phpbook-dsssl/html.dsl -V nochunks -t sgml $(PHPDOC)/phpbook/phpbook-xml/phpdocxml.dcl manual.xml > manual.html
  625. tex: manual.tex
  626. manual.tex: confcheck manual.xml
  627. \tSP_ENCODING=XML SP_CHARSET_FIXED=YES openjade -D $(PHPDOC) -wno-idref -c $(PHPDOC)/docbook/docbook-dsssl/catalog -c $(PHPDOC)/phpbook/phpbook-dsssl/defaults/catalog -d $(PHPDOC)/phpbook/phpbook-dsssl/print.dsl -t tex $(PHPDOC)/phpbook/phpbook-xml/phpdocxml.dcl manual.xml
  628. pdf: manual.tex
  629. \tpdfjadetex manual.tex && pdfjadetex manual.tex && pdfjadetex manual.tex
  630. ");
  631. $makefile->close();
  632. $entities = new CodeGen_Tools_FileReplacer("$docdir/file-entities.ent");
  633. $entities->puts("<!ENTITY reference.$idName.reference SYSTEM './$idName/reference.xml'>\n");
  634. $fp = new CodeGen_Tools_FileReplacer("$docdir/$idName/reference.xml");
  635. $fp->puts(
  636. "<?xml version='1.0' encoding='iso-8859-1'?>
  637. <!-- ".'$'."Revision: 1.1 $ -->
  638. ");
  639. // phpdoc comments according to http://doc.php.net/php/de/dochowto/x1257.php
  640. $fp->puts("<!-- Purpose: ".$this->docPurpose." -->\n");
  641. $fp->puts("<!-- Membership: pecl");
  642. if (count($this->with)) {
  643. $fp->puts(", external");
  644. }
  645. $fp->puts(" -->\n");
  646. if ($this->release->getState() !== 'stable') {
  647. $fp->puts("<!-- State: experimental -->\n");
  648. }
  649. $fp->puts("
  650. <reference xml:id='ref.$idName' xmlns='http://docbook.org/ns/docbook' xmlns:xlink='http://www.w3.org/1999/xlink'>
  651. <title>{$this->summary}</title>
  652. <titleabbrev>$idName</titleabbrev>
  653. <partintro>
  654. <section id='$idName.intro'>
  655. &reftitle.intro;
  656. <para>
  657. {$this->description}
  658. </para>
  659. </section>
  660. <section xml:id='$idName.requirements'>
  661. &reftitle.required;
  662. <para>
  663. </para>
  664. </section>
  665. &reference.$idName.configure;
  666. &reference.extname.ini;
  667. <section id='$idName.resources'>
  668. &reftitle.resources;
  669. ");
  670. if (empty($this->resources)) {
  671. $fp->puts(" &no.resource;\n");
  672. } else {
  673. foreach ($this->resources as $resource) {
  674. $fp->puts($resource->docEntry($idName));
  675. }
  676. }
  677. $fp->puts(
  678. " </section>
  679. &reference.extname.constants;
  680. </partintro>
  681. &reference.$idName.functions;
  682. </reference>
  683. ");
  684. $fp->puts($this->docEditorSettings());
  685. $fp->close();
  686. //
  687. // constants.xml
  688. //
  689. $entities->puts("<!ENTITY reference.$idName.constants SYSTEM './$idName/constants.xml'>\n");
  690. $fp = new CodeGen_Tools_FileReplacer("$docdir/$idName/constants.xml");
  691. $fp->puts(
  692. "<?xml version='1.0' encoding='iso-8859-1'?>
  693. <!-- ".'$'."Revision: 1.1 $ -->
  694. ");
  695. $fp->puts("<section id='$idName.constants' xmlns='http://docbook.org/ns/docbook' xmlns:xlink='http://www.w3.org/1999/xlink'>\n");
  696. $fp->puts(" &reftitle.constants;\n");
  697. $fp->puts(" &extension.constants;\n");
  698. $fp->puts(" <para>\n");
  699. if (empty($this->constants)) {
  700. $fp->puts(" &no.constants;\n");
  701. } else {
  702. $const_groups = array();
  703. foreach ($this->constants as $constant) {
  704. $const_groups[$constant->getGroup()][] = $constant;
  705. }
  706. foreach ($const_groups as $group => $constants) {
  707. if ($group == "default") {
  708. $group = $idName;
  709. }
  710. $fp->puts(CodeGen_PECL_Element_Constant::docHeader($group));
  711. foreach ($constants as $constant) {
  712. $fp->puts($constant->docEntry($group));
  713. }
  714. $fp->puts(CodeGen_PECL_Element_Constant::docFooter());
  715. }
  716. }
  717. // TODO: 2nd half missing, see http://doc.php.net/php/de/dochowto/c578.php
  718. $fp->puts(" </para>\n");
  719. $fp->puts("</section>\n");
  720. $fp->puts($this->docEditorSettings());
  721. $fp->close();
  722. //
  723. // ini.xml
  724. //
  725. $entities->puts("<!ENTITY reference.$idName.ini SYSTEM './$idName/ini.xml'>\n");
  726. $fp = new CodeGen_Tools_FileReplacer("$docdir/$idName/ini.xml");
  727. $fp->puts(
  728. "<?xml version='1.0' encoding='iso-8859-1'?>
  729. <!-- ".'$'."Revision: 1.1 $ -->
  730. ");
  731. $fp->puts("<section id='$idName.configuration' xmlns='http://docbook.org/ns/docbook' xmlns:xlink='http://www.w3.org/1999/xlink'>\n");
  732. $fp->puts(" &reftitle.runtime;\n");
  733. $fp->puts(" &extension.runtime;\n");
  734. $fp->puts(" <para>\n");
  735. if (empty($this->phpini)) {
  736. $fp->puts(" &no.config;\n");
  737. } else {
  738. $fp->puts(CodeGen_PECL_Element_Ini::docHeader($this->name));
  739. foreach ($this->phpini as $phpini) {
  740. $fp->puts($phpini->docEntry($idName));
  741. }
  742. $fp->puts(CodeGen_PECL_Element_Ini::docFooter());
  743. }
  744. $fp->puts(" </para>\n");
  745. $fp->puts("</section>\n");
  746. $fp->puts($this->docEditorSettings());
  747. $fp->close();
  748. //
  749. // configure.xml
  750. //
  751. // configure options and dependencies have their own file
  752. $entities->puts("<!ENTITY reference.$idName.configure SYSTEM './$idName/configure.xml'>\n");
  753. $fp = new CodeGen_Tools_FileReplacer("$docdir/$idName/configure.xml");
  754. $fp->puts(
  755. "<?xml version='1.0' encoding='iso-8859-1'?>
  756. <!-- ".'$'."Revision: 1.1 $ -->
  757. ");
  758. $fp->puts("\n <section id='$idName.requirements'>\n &reftitle.required;\n");
  759. // TODO headers and libs are now "hidden" in $with
  760. if (empty($this->libs) && empty($this->headers)) {
  761. $fp->puts(" &no.requirement;\n");
  762. } else {
  763. // TODO allow custom text
  764. if (isset($this->libs)) {
  765. $libs = array();
  766. foreach ($this->libs as $lib) {
  767. $libs[] = $lib->getName();
  768. }
  769. $ies = count($libs)>1 ? "ies" :"y";
  770. $fp->puts("<para>This extension requires the following librar$ies: ".join(",", $libs)."</para>\n");
  771. }
  772. if (isset($this->headers)) {
  773. $headers = array();
  774. foreach ($this->headers as $header) {
  775. $headers[] = $header->getName();
  776. }
  777. $s = count($headers)>1 ? "s" : "";
  778. $fp->puts("<para>This extension requires the following header$s: ".join(",", $headers)."</para>\n");
  779. }
  780. }
  781. $fp->puts("\n </section>\n\n");
  782. $fp->puts("\n <section id='$idName.install'>\n &reftitle.install;\n");
  783. if (empty($this->with)) {
  784. $fp->puts(" &no.install;\n");
  785. } else {
  786. foreach ($this->with as $with) {
  787. if (isset($with->summary)) {
  788. if (strstr($with->summary, "<para>")) {
  789. $fp->puts($with->summary);
  790. } else {
  791. $fp->puts(" <para>\n".rtrim($with->summary)."\n </para>\n");
  792. }
  793. } else {
  794. $fp->puts(" <para>Requires <literal>".$with->getName()."</literal></para>\n");
  795. }
  796. }
  797. }
  798. $fp->puts("\n </section>\n\n");
  799. $fp->puts($this->docEditorSettings());
  800. $fp->close();
  801. //
  802. $function_entities = array();
  803. @mkdir("$docdir/$idName/functions");
  804. foreach ($this->functions as $name => $function) {
  805. $functionId = strtolower(str_replace("_", "-", $name));
  806. $filepath = "$idName/functions/$functionId.xml";
  807. $entity = "reference.$idName.functions.$functionId";
  808. $function_entities[] = $entity;
  809. $entities->puts("<!ENTITY $entity SYSTEM './$filepath'>\n");
  810. $funcfile = new CodeGen_Tools_FileReplacer("$docdir$filepath");
  811. $funcfile->puts($function->docEntry($idName));
  812. $funcfile->puts($this->docEditorSettings(4));
  813. $funcfile->close();
  814. }
  815. $entities->puts("<!ENTITY reference.$idName.functions SYSTEM './functions.xml'>\n");
  816. $entities->close();
  817. $functionsXml = new CodeGen_Tools_FileReplacer($docdir."/functions.xml");
  818. sort($function_entities);
  819. foreach ($function_entities as $entity) {
  820. $functionsXml->puts(" &$entity;\n");
  821. }
  822. $functionsXml->close();
  823. }
  824. // }}}
  825. // {{{ extension entry
  826. /**
  827. * Create the module entry code for this extension
  828. *
  829. * @access private
  830. * @return string zend_module_entry code fragment
  831. */
  832. function generateExtensionEntry()
  833. {
  834. $name = $this->name;
  835. $upname = strtoupper($this->name);
  836. $code = "";
  837. if (empty($this->otherExtensions)) {
  838. $moduleHeader = " STANDARD_MODULE_HEADER,";
  839. } else {
  840. $code.= CodeGen_PECL_Dependency_Extension::cCodeHeader($this);
  841. foreach ($this->otherExtensions as $ext) {
  842. $code.= $ext->cCode($this);
  843. }
  844. $code.= CodeGen_PECL_Dependency_Extension::cCodeFooter($this);
  845. $moduleHeader =
  846. "#if ZEND_EXTENSION_API_NO >= 220050617
  847. STANDARD_MODULE_HEADER_EX, NULL,
  848. {$this->name}_deps,
  849. #else
  850. STANDARD_MODULE_HEADER,
  851. #endif
  852. ";
  853. }
  854. $code.= "
  855. /* {{{ {$name}_module_entry
  856. */
  857. zend_module_entry {$name}_module_entry = {
  858. $moduleHeader
  859. \"$name\",
  860. {$name}_functions,
  861. PHP_MINIT($name), /* Replace with NULL if there is nothing to do at php startup */
  862. PHP_MSHUTDOWN($name), /* Replace with NULL if there is nothing to do at php shutdown */
  863. PHP_RINIT($name), /* Replace with NULL if there is nothing to do at request start */
  864. PHP_RSHUTDOWN($name), /* Replace with NULL if there is nothing to do at request end */
  865. PHP_MINFO($name),
  866. PHP_".$upname."_VERSION,
  867. STANDARD_MODULE_PROPERTIES
  868. };
  869. /* }}} */
  870. ";
  871. $code .= "#ifdef COMPILE_DL_$upname\n";
  872. if ($this->language == "cpp") {
  873. $code .= "extern \"C\" {\n";
  874. }
  875. $code .= "ZEND_GET_MODULE($name)\n";
  876. if ($this->language == "cpp") {
  877. $code .= "} // extern \"C\"\n";
  878. }
  879. $code .= "#endif\n\n";
  880. return $code;
  881. }
  882. // }}}
  883. // {{{ globals and ini
  884. /**
  885. * Create the module globals c code fragment
  886. *
  887. * @access private
  888. * @return string module globals code fragment
  889. */
  890. function generateGlobalsC()
  891. {
  892. if (empty($this->globals)) return "";
  893. $code = "\n/* {{{ globals and ini entries */\n";
  894. $code .= "ZEND_DECLARE_MODULE_GLOBALS({$this->name})\n\n";
  895. if (!empty($this->phpini)) {
  896. $code .= CodeGen_PECL_Element_Ini::cCodeHeader($this->name);
  897. foreach ($this->phpini as $phpini) {
  898. $code .= $phpini->cCode($this->name);
  899. }
  900. $code .= CodeGen_PECL_Element_Ini::cCodeFooter($this->name);
  901. }
  902. if (!empty($this->globals)) {
  903. $code .= CodeGen_PECL_Element_Global::cCodeHeader($this->name);
  904. foreach ($this->globals as $global) {
  905. $code .= $global->cCode($this->name);
  906. }
  907. $code .= CodeGen_PECL_Element_Global::cCodeFooter($this->name);
  908. }
  909. $code .= "/* }}} */\n\n";
  910. return $code;
  911. }
  912. /**
  913. * Create the module globals c header file fragment
  914. *
  915. * @access private
  916. * @return string module globals code fragment
  917. */
  918. function generateGlobalsH()
  919. {
  920. if (empty($this->globals)) return "";
  921. $code = CodeGen_PECL_Element_Global::hCodeHeader($this->name);
  922. foreach ($this->globals as $global) {
  923. $code .= $global->hCode($this->name);
  924. }
  925. $code .= CodeGen_PECL_Element_Global::hCodeFooter($this->name);
  926. return $code;
  927. }
  928. // }}}
  929. // {{{
  930. /**
  931. * Create global function registration
  932. *
  933. * @access private
  934. * @return string function registration code fragments
  935. */
  936. function generateFunctionRegistrations()
  937. {
  938. $code = "/* {{{ {$this->name}_functions[] */\n";
  939. $code .= "function_entry {$this->name}_functions[] = {\n";
  940. foreach ($this->functions as $function) {
  941. $code.= $function->functionEntry();
  942. }
  943. foreach ($this->classes as $class) {
  944. $code.= $class->functionAliasEntries();
  945. }
  946. $code .= " { NULL, NULL, NULL }\n";
  947. $code .= "};\n/* }}} */\n\n";
  948. return $code;
  949. }
  950. // }}}
  951. // {{{
  952. /**
  953. * Create global class registration code and functions
  954. *
  955. * @access private
  956. * @return string class registration code fragments
  957. */
  958. function generateClassRegistrations()
  959. {
  960. if (empty($this->classes)) return "";
  961. $code = "/* {{{ Class definitions */\n\n";
  962. foreach ($this->classes as $class) {
  963. $code .= $class->globalCode($this);
  964. }
  965. $code .= "/* }}} Class definitions*/\n\n";
  966. return $code;
  967. }
  968. // }}}
  969. // {{{
  970. /**
  971. * Create global interface registration code
  972. *
  973. * @access private
  974. * @return string interface registration code fragments
  975. */
  976. function generateInterfaceRegistrations()
  977. {
  978. if (empty($this->interfaces)) return "";
  979. $code = "/* {{{ Interface definitions */\n\n";
  980. foreach ($this->interfaces as $interface) {
  981. $code .= $interface->globalCode($this);
  982. }
  983. $code .= "/* }}} Interface definitions*/\n\n";
  984. return $code;
  985. }
  986. // }}}
  987. // {{{ license and authoers
  988. /**
  989. * Set license
  990. *
  991. * @access public
  992. * @param object
  993. */
  994. function setLicense($license)
  995. {
  996. if (preg_match("|^GPL|", $license->getShortName())) {
  997. return PEAR::raiseError("The ".$license->getShortName().
  998. "is not a valid choice for PHP extensions due to license incompatibilities");
  999. }
  1000. $this->license = $license;
  1001. return true;
  1002. }
  1003. /**
  1004. * Create the license part of the source file header comment
  1005. *
  1006. * @access private
  1007. * @return string code fragment
  1008. */
  1009. function getLicenseComment()
  1010. {
  1011. $code = "/*\n";
  1012. $code.= " +----------------------------------------------------------------------+\n";
  1013. if (is_object($this->license)) {
  1014. $code.= $this->license->getComment();
  1015. } else {
  1016. $code.= sprintf(" | unknown license: %-52s |\n", $this->license);
  1017. }
  1018. $code.= " +----------------------------------------------------------------------+\n";
  1019. foreach ($this->authors as $author) {
  1020. $code.= $author->comment();
  1021. }
  1022. $code.= " +----------------------------------------------------------------------+\n";
  1023. $code.= "*/\n\n";
  1024. $code.= "/* $ Id: $ */ \n\n";
  1025. return $code;
  1026. }
  1027. // }}}
  1028. /**
  1029. * Set pear installer channel
  1030. *
  1031. * @access public
  1032. * @param string
  1033. */
  1034. function setChannel($channel)
  1035. {
  1036. if (! preg_match('/^[a-z\-_\.]+$/i', $channel)) {
  1037. return PEAR::raiseError("'$channel' is not a valid pear installer channel name");
  1038. }
  1039. $this->channel = $channel;
  1040. }
  1041. // {{{ header file
  1042. /**
  1043. * Write the complete C header file
  1044. *
  1045. * @access private
  1046. * @param string directory to write to
  1047. */
  1048. function writeHeaderFile()
  1049. {
  1050. $this->addPackageFile('header', "php_{$this->name}.h");
  1051. $file = new CodeGen_Tools_Outbuf($this->dirpath."/php_{$this->name}.h");
  1052. $upname = strtoupper($this->name);
  1053. echo $this->getLicenseComment();
  1054. echo "#ifndef PHP_{$upname}_H\n";
  1055. echo "#define PHP_{$upname}_H\n\n";
  1056. foreach ($this->headers as $header) {
  1057. echo $header->hCode(true);
  1058. }
  1059. echo "#ifdef __cplusplus\n";
  1060. echo "extern \"C\" {\n";
  1061. echo "#endif\n";
  1062. echo '
  1063. #ifdef HAVE_CONFIG_H
  1064. #include "config.h"
  1065. #endif
  1066. #include <php.h>
  1067. #ifdef HAVE_'.$upname.'
  1068. ';
  1069. echo '#define PHP_'.$upname.'_VERSION "'.$this->release->getVersion().'"'."\n\n";
  1070. echo '
  1071. #include <php_ini.h>
  1072. #include <SAPI.h>
  1073. #include <ext/standard/info.h>
  1074. #include <Zend/zend_extensions.h>
  1075. ';
  1076. echo "#ifdef __cplusplus\n";
  1077. echo "} // extern \"C\" \n";
  1078. echo "#endif\n";
  1079. foreach ($this->headers as $header) {
  1080. echo $header->hCode(false);
  1081. }
  1082. foreach ($this->with as $with) {
  1083. foreach ($with->getHeaders() as $header) {
  1084. echo $header->hCode(false);
  1085. }
  1086. }
  1087. if (isset($this->code["header"]["top"])) {
  1088. foreach ($this->code["header"]["top"] as $code) {
  1089. echo $this->codegen->block($code, 0);
  1090. }
  1091. }
  1092. echo "#ifdef __cplusplus\n";
  1093. echo "extern \"C\" {\n";
  1094. echo "#endif\n";
  1095. echo "
  1096. extern zend_module_entry {$this->name}_module_entry;
  1097. #define phpext_{$this->name}_ptr &{$this->name}_module_entry
  1098. #ifdef PHP_WIN32
  1099. #define PHP_{$upname}_API __declspec(dllexport)
  1100. #else
  1101. #define PHP_{$upname}_API
  1102. #endif
  1103. PHP_MINIT_FUNCTION({$this->name});
  1104. PHP_MSHUTDOWN_FUNCTION({$this->name});
  1105. PHP_RINIT_FUNCTION({$this->name});
  1106. PHP_RSHUTDOWN_FUNCTION({$this->name});
  1107. PHP_MINFO_FUNCTION({$this->name});
  1108. #ifdef ZTS
  1109. #include \"TSRM.h\"
  1110. #endif
  1111. #define FREE_RESOURCE(resource) zend_list_delete(Z_LVAL_P(resource))
  1112. #define PROP_GET_LONG(name) Z_LVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC))
  1113. #define PROP_SET_LONG(name, l) zend_update_property_long(_this_ce, _this_zval, #name, strlen(#name), l TSRMLS_CC)
  1114. #define PROP_GET_DOUBLE(name) Z_DVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC))
  1115. #define PROP_SET_DOUBLE(name, d) zend_update_property_double(_this_ce, _this_zval, #name, strlen(#name), d TSRMLS_CC)
  1116. #define PROP_GET_STRING(name) Z_STRVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC))
  1117. #define PROP_GET_STRLEN(name) Z_STRLEN_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC))
  1118. #define PROP_SET_STRING(name, s) zend_update_property_string(_this_ce, _this_zval, #name, strlen(#name), s TSRMLS_CC)
  1119. #define PROP_SET_STRINGL(name, s, l) zend_update_property_stringl(_this_ce, _this_zval, #name, strlen(#name), s, l TSRMLS_CC)
  1120. ";
  1121. echo $this->generateGlobalsH();
  1122. echo "\n";
  1123. foreach ($this->functions as $name => $function) {
  1124. echo $function->hCode($this);
  1125. }
  1126. foreach ($this->classes as $name => $class) {
  1127. echo $class->hCode($this);
  1128. }
  1129. foreach ($this->interfaces as $name => $interface) {
  1130. echo $interface->hCode($this);
  1131. }
  1132. foreach ($this->streams as $name => $stream) {
  1133. echo $this->codegen->block($stream->hCode());
  1134. }
  1135. echo "#ifdef __cplusplus\n";
  1136. echo "} // extern \"C\" \n";
  1137. echo "#endif\n";
  1138. echo "\n";
  1139. // write #defines for <constant>s
  1140. $defines = "";
  1141. foreach ($this->constants as $constant) {
  1142. $defines.= $constant->hCode($this);
  1143. }
  1144. if ($defines !== "") {
  1145. echo "/* mirrored PHP Constants */\n";
  1146. echo $defines;
  1147. echo "\n";
  1148. }
  1149. // add bottom header snippets
  1150. if (isset($this->code["header"]["bottom"])) {
  1151. echo "/* 'bottom' header snippets*/\n";
  1152. foreach ($this->code["header"]["bottom"] as $code) {
  1153. echo $this->codegen->block($code, 0);
  1154. }
  1155. echo "\n";
  1156. }
  1157. echo "#endif /* PHP_HAVE_{$upname} */\n\n";
  1158. echo "#endif /* PHP_{$upname}_H */\n\n";
  1159. echo $this->cCodeEditorSettings();
  1160. return $file->write();
  1161. }
  1162. // }}}
  1163. // {{{ internal functions
  1164. /**
  1165. * Create code for the internal functions like MINIT etc ...
  1166. *
  1167. * @access private
  1168. * @return string code snippet
  1169. */
  1170. function internalFunctionsC()
  1171. {
  1172. $need_block = false;
  1173. $code = "
  1174. /* {{{ PHP_MINIT_FUNCTION */
  1175. PHP_MINIT_FUNCTION({$this->name})
  1176. {
  1177. ";
  1178. if (count($this->globals)) {
  1179. $code .= " ZEND_INIT_MODULE_GLOBALS({$this->name}, php_{$this->name}_init_globals, php_{$this->name}_shutdown_globals)\n";
  1180. $need_block = true;
  1181. }
  1182. if (count($this->phpini)) {
  1183. $code .= " REGISTER_INI_ENTRIES();\n";
  1184. $need_block = true;
  1185. }
  1186. foreach ($this->logos as $logo) {
  1187. $code .= $this->codegen->block($logo->minitCode());
  1188. $need_block = true;
  1189. }
  1190. if (count($this->constants)) {
  1191. foreach ($this->constants as $constant) {
  1192. $code .= $this->codegen->block($constant->cCode($this->name));
  1193. }
  1194. $need_block = true;
  1195. }
  1196. if (count($this->resources)) {
  1197. foreach ($this->resources as $resource) {
  1198. $code .= $this->codegen->block($resource->minitCode());
  1199. }
  1200. $need_block = true;
  1201. }
  1202. if (count($this->interfaces)) {
  1203. foreach ($this->interfaces as $interface) {
  1204. $code .= $this->codegen->block($interface->minitCode($this));
  1205. }
  1206. $need_block = true;
  1207. }
  1208. if (count($this->classes)) {
  1209. foreach ($this->classes as $class) {
  1210. $code .= $this->codegen->block($class->minitCode($this));
  1211. }
  1212. $need_block = true;
  1213. }
  1214. if (count($this->streams)) {
  1215. foreach ($this->streams as $stream) {
  1216. $code .= $this->codegen->block($stream->minitCode($this));
  1217. }
  1218. $need_block = true;
  1219. }
  1220. if (isset($this->internalFunctions['MINIT'])) {
  1221. $code .= $this->codegen->varblock($this->internalFunctions['MINIT']->getCode());
  1222. } else {
  1223. $code .="\n /* add your stuff here */\n";
  1224. }
  1225. $code .= "
  1226. return SUCCESS;
  1227. }
  1228. /* }}} */
  1229. ";
  1230. $code .= "
  1231. /* {{{ PHP_MSHUTDOWN_FUNCTION */
  1232. PHP_MSHUTDOWN_FUNCTION({$this->name})
  1233. {
  1234. ";
  1235. if (count($this->phpini)) {
  1236. $code .= " UNREGISTER_INI_ENTRIES();\n";
  1237. $need_block = true;
  1238. }
  1239. // TODO: need to destruct globals here if in ZTS mode!!111
  1240. if (count($this->logos)) {
  1241. foreach ($this->logos as $logo) {
  1242. $code .= $this->codegen->block($logo->mshutdownCode());
  1243. }
  1244. $need_block = true;
  1245. }
  1246. if (isset($this->internalFunctions['MSHUTDOWN'])) {
  1247. $code .= $this->codegen->varblock($this->internalFunctions['MSHUTDOWN']->getCode());
  1248. } else {
  1249. $code .="\n /* add your stuff here */\n";
  1250. }
  1251. $code .= "
  1252. return SUCCESS;
  1253. }
  1254. /* }}} */
  1255. ";
  1256. $code .= "
  1257. /* {{{ PHP_RINIT_FUNCTION */
  1258. PHP_RINIT_FUNCTION({$this->name})
  1259. {
  1260. ";
  1261. if (isset($this->internalFunctions['RINIT'])) {
  1262. $code .= $this->codegen->block($this->internalFunctions['RINIT']->getCode());
  1263. } else {
  1264. $code .= " /* add your stuff here */\n";
  1265. }
  1266. $code .= "
  1267. return SUCCESS;
  1268. }
  1269. /* }}} */
  1270. ";
  1271. $code .= "
  1272. /* {{{ PHP_RSHUTDOWN_FUNCTION */
  1273. PHP_RSHUTDOWN_FUNCTION({$this->name})
  1274. {
  1275. ";
  1276. if (isset($this->internalFunctions['RSHUTDOWN'])) {
  1277. $code .= $this->codegen->block($this->internalFunctions['RSHUTDOWN']->getCode());
  1278. } else {
  1279. $code .= " /* add your stuff here */\n";
  1280. }
  1281. $code .= "
  1282. return SUCCESS;
  1283. }
  1284. /* }}} */
  1285. ";
  1286. $code .= "
  1287. /* {{{ PHP_MINFO_FUNCTION */
  1288. PHP_MINFO_FUNCTION({$this->name})
  1289. {
  1290. ";
  1291. if (!empty($this->logos)) {
  1292. $code.= " if (!sapi_module.phpinfo_as_text) {\n";
  1293. foreach ($this->logos as $logo) {
  1294. $code.= $logo->phpinfoCode($this->name);
  1295. }
  1296. echo " }\n";
  1297. }
  1298. if (!empty($this->summary)) {
  1299. $summary = strtr(trim($this->summary), array('"'=>'\\"'));
  1300. $code .= " php_printf(\"$summary\\n\");\n";
  1301. }
  1302. $code.= " php_info_print_table_start();\n";
  1303. if (!empty($this->release)) {
  1304. $code .= $this->release->phpinfoCode($this->name);
  1305. }
  1306. if (count($this->authors)) {
  1307. $code.= ' php_info_print_table_row(2, "Authors", "';
  1308. foreach ($this->authors as $author) {
  1309. $code.= $author->phpinfoCode($this->name).'\\n';
  1310. }
  1311. $code.= "\");\n";
  1312. }
  1313. $code.=
  1314. " php_info_print_table_end();
  1315. ";
  1316. // TODO move this decision up?
  1317. if (isset($this->internalFunctions['MINFO'])) {
  1318. $code .= $this->codegen->varblock($this->internalFunctions['MINFO']->getCode());
  1319. } else {
  1320. $code .= " /* add your stuff here */\n";
  1321. }
  1322. if (count($this->phpini)) {
  1323. $code .= "\n DISPLAY_INI_ENTRIES();";
  1324. }
  1325. $code .= "
  1326. }
  1327. /* }}} */
  1328. ";
  1329. return $code;
  1330. }
  1331. // }}}
  1332. // {{{ public functions
  1333. /**
  1334. * Create code for the exported PHP functions
  1335. *
  1336. * @access private
  1337. * @return string code snippet
  1338. */
  1339. function publicFunctionsC()
  1340. {
  1341. $code = "";
  1342. foreach ($this->functions as $function) {
  1343. $code .= $function->cCode($this);
  1344. }
  1345. return $code;
  1346. }
  1347. // }}}
  1348. // {{{ code file
  1349. /**
  1350. * Write the complete C code file
  1351. *
  1352. * @access private
  1353. * @param string directory to write to
  1354. */
  1355. function writeCodeFile()
  1356. {
  1357. $filename = "{$this->name}.{$this->language}"; // todo extension logic
  1358. $upname = strtoupper($this->name);
  1359. $this->addPackageFile('code', $filename);
  1360. $file = new CodeGen_Tools_Outbuf($this->dirpath.'/'.$filename, CodeGen_Tools_Outbuf::OB_TABIFY);
  1361. echo $this->getLicenseComment();
  1362. echo "#include \"php_{$this->name}.h\"\n\n";
  1363. echo "#if HAVE_$upname\n\n";
  1364. if (isset($this->code["code"]["top"])) {
  1365. foreach ($this->code["code"]["top"] as $code) {
  1366. echo $this->codegen->block($code, 0);
  1367. }
  1368. }
  1369. if (!empty($this->logos)) {
  1370. echo CodeGen_PECL_Element_Logo::cCodeHeader($this->name);
  1371. foreach ($this->logos as $logo) {
  1372. echo $logo->cCode($this->name);
  1373. }
  1374. echo CodeGen_PECL_Element_Logo::cCodeFooter($this->name);
  1375. }
  1376. if (!empty($this->resources)) {
  1377. echo CodeGen_PECL_Element_Resource::cCodeHeader($this->name);
  1378. foreach ($this->resources as $resource) {
  1379. echo $resource->cCode($this);
  1380. }
  1381. echo CodeGen_PECL_Element_Resource::cCodeFooter($this->name);
  1382. }
  1383. echo $this->generateInterfaceRegistrations();
  1384. echo $this->generateClassRegistrations();
  1385. echo $this->generateFunctionRegistrations();
  1386. echo $this->generateExtensionEntry();
  1387. echo $this->generateGlobalsC();
  1388. echo $this->internalFunctionsC();
  1389. echo $this->publicFunctionsC();
  1390. if (isset($this->code["code"]["bottom"])) {
  1391. foreach ($this->code["code"]["bottom"] as $code) {
  1392. echo $this->codegen->block($code, 0);
  1393. }
  1394. }
  1395. echo "#endif /* HAVE_$upname */\n\n";
  1396. echo $this->cCodeEditorSettings();
  1397. return $file->write();
  1398. }
  1399. // }}}
  1400. // {{{ config.m4 file
  1401. /**
  1402. * Write config.m4 file for autoconf
  1403. *
  1404. * @access private
  1405. * @param string directory to write to
  1406. */
  1407. function writeConfigM4()
  1408. {
  1409. $upname = strtoupper($this->name);
  1410. $this->addPackageFile("conf", "config.m4");
  1411. $file = new CodeGen_Tools_Outbuf($this->dirpath."/config.m4", CodeGen_Tools_Outbuf::OB_TABIFY);
  1412. echo
  1413. 'dnl
  1414. dnl $ Id: $
  1415. dnl
  1416. ';
  1417. if (isset($this->with[$this->name])) {
  1418. $with = $this->with[$this->name];
  1419. echo "\n".$with->m4Line()."\n";
  1420. } else {
  1421. echo "
  1422. PHP_ARG_ENABLE({$this->name}, whether to enable {$this->name} functions,
  1423. [ --enable-{$this->name} Enable {$this->name} support])
  1424. ";
  1425. }
  1426. echo "\n";
  1427. echo "if test \"\$PHP_$upname\" != \"no\"; then\n";
  1428. if ($this->language === "cpp") {
  1429. echo " PHP_REQUIRE_CXX\n";
  1430. echo " AC_LANG_CPLUSPLUS\n";
  1431. echo " PHP_ADD_LIBRARY(stdc++,,{$upname}_SHARED_LIBADD)\n";
  1432. }
  1433. foreach ($this->configfragments['top'] as $fragment) {
  1434. echo "$fragment\n";
  1435. }
  1436. foreach ($this->with as $with) {
  1437. echo $with->configm4($this);
  1438. }
  1439. $pathes = array();
  1440. foreach ($this->headers as $header) {
  1441. $pathes[$header->getPath()] = true; // TODO WTF???
  1442. }
  1443. foreach (array_keys($pathes) as $path) {
  1444. echo " PHP_ADD_INCLUDE(\$PHP_{$upname}_DIR/$path)\n";
  1445. }
  1446. echo " export OLD_CPPFLAGS=\"\$CPPFLAGS\"\n";
  1447. echo " export CPPFLAGS=\"\$CPPFLAGS \$INCLUDES -DHAVE_".strtoupper($this->name)."\"\n";
  1448. echo "
  1449. AC_MSG_CHECKING(PHP version)
  1450. AC_TRY_COMPILE([#include <php_version.h>], [
  1451. #if PHP_VERSION_ID < ".$this->minPhpVersionId()."
  1452. #error this extension requires at least PHP version ".$this->minPhpVersion()."
  1453. #endif
  1454. ],
  1455. [AC_MSG_RESULT(ok)],
  1456. [AC_MSG_ERROR([need at least PHP ".$this->minPhpVersion()."])])
  1457. ";
  1458. if (count($this->headers)) {
  1459. if (!isset($this->with[$this->name])) {
  1460. $this->terminate("global headers not bound to a --with option found and no --with option by the default name");
  1461. }
  1462. foreach ($this->headers as $header) {
  1463. echo $header->configm4($this->name, $this->name);
  1464. }
  1465. }
  1466. foreach ($this->resources as $resource) {
  1467. echo $resource->configm4($this->name);
  1468. }
  1469. echo " export CPPFLAGS=\"\$OLD_CPPFLAGS\"\n";
  1470. if (count($this->libs)) {
  1471. if (!isset($this->with[$this->name])) {
  1472. $this->terminate("global libs not bound to a --with option found and no --with option by the default name");
  1473. }
  1474. foreach ($this->libs as $lib) {
  1475. echo $lib->configm4($this->name, $this->name);
  1476. }
  1477. }
  1478. echo "\n";
  1479. echo "
  1480. PHP_SUBST({$upname}_SHARED_LIBADD)
  1481. AC_DEFINE(HAVE_$upname, 1, [ ])
  1482. ";
  1483. foreach ($this->defines as $define) {
  1484. echo " AC_DEFINE([$define[name]], [$define[value]], [$define[comment]])\n";
  1485. }
  1486. echo "
  1487. PHP_NEW_EXTENSION({$this->name}, ".join(" ", array_keys($this->packageFiles['code']))." , \$ext_shared)
  1488. ";
  1489. if (count($this->makefragments)) {
  1490. echo " PHP_ADD_MAKEFILE_FRAGMENT\n";
  1491. $frag = new CodeGen_Tools_FileReplacer($this->dirpath."/Makefile.frag");
  1492. foreach ($this->makefragments as $block) {
  1493. $frag->puts(CodeGen_Tools_IndentC::tabify("\n$block\n"));
  1494. }
  1495. $frag->close();
  1496. }
  1497. foreach ($this->configfragments['bottom'] as $fragment) {
  1498. echo "$fragment\n";
  1499. }
  1500. echo
  1501. "
  1502. fi
  1503. ";
  1504. return $file->write();
  1505. }
  1506. // }}}
  1507. // {{{ config.w32 file
  1508. /**
  1509. * Write config.w32 file for new windows build system
  1510. *
  1511. * @access private
  1512. * @param string directory to write to
  1513. */
  1514. function writeConfigW32()
  1515. {
  1516. // TODO fragments
  1517. $upname = strtoupper($this->name);
  1518. $this->addPackageFile("conf", "config.w32");
  1519. $file = new CodeGen_Tools_Outbuf($this->dirpath."/config.w32",
  1520. CodeGen_Tools_Outbuf::OB_UNTABIFY
  1521. | CodeGen_Tools_Outbuf::OB_DOSIFY);
  1522. echo
  1523. '// $ Id: $
  1524. // vim:ft=javascript
  1525. ';
  1526. if (isset($this->with[$this->name])) {
  1527. echo "
  1528. ARG_WITH('{$this->name}', '{$this->summary}', 'no');
  1529. ";
  1530. } else {
  1531. echo "
  1532. ARG_ENABLE('{$this->name}' , '{$this->summary}', 'no');
  1533. ";
  1534. }
  1535. echo "if (PHP_$upname == \"yes\") {\n";
  1536. // add libraries from <deps> section
  1537. foreach ($this->libs as $lib) {
  1538. echo $lib->configw32($this->name, $this->name);
  1539. }
  1540. foreach ($this->headers as $header) {
  1541. echo $header->configw32($this->name, $this->name);
  1542. }
  1543. echo " EXTENSION(\"{$this->name}\", \"".join(" ", array_keys($this->packageFiles['code']))."\");\n";
  1544. echo " AC_DEFINE(\"HAVE_$upname\", 1, \"{$this->name} support\");\n";
  1545. foreach ($this->defines as $define) {
  1546. echo " AC_DEFINE(\"$define[name]\", $define[value], \"$define[comment]\")\n";
  1547. }
  1548. echo "}\n";
  1549. $file->write();
  1550. }
  1551. // }}}
  1552. // {{{ M$ dev studio project file
  1553. /**
  1554. * Write project file for VisualStudio V6
  1555. *
  1556. * @access private
  1557. * @param string directory to write to
  1558. */
  1559. function writeMsDevStudioDsp()
  1560. {
  1561. $filename = $this->name.".dsp";
  1562. $this->addPackageFile("conf", $filename);
  1563. $file = new CodeGen_Tools_Outbuf($this->dirpath.'/'.$filename,
  1564. CodeGen_Tools_Outbuf::OB_UNTABIFY
  1565. | CodeGen_Tools_Outbuf::OB_DOSIFY);
  1566. // these system libraries are always needed?
  1567. // (list taken from sample *.dsp files in php ext tree...)
  1568. $winlibs = "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib ";
  1569. $winlibs.= "shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib";
  1570. // add libraries from <deps> section
  1571. if (count($this->libs)) {
  1572. foreach ($this->libs as $lib) {
  1573. if (!$lib->testPlatform("windows")) {
  1574. continue;
  1575. }
  1576. $winlibs .= " ".$lib->getName().".lib";
  1577. }
  1578. }
  1579. $defines = '/D HAVE_'.strtoupper($this->name).'=1 ';
  1580. foreach ($this->defines as $define) {
  1581. $defines = '/D "'.$define['name'].'='.$define['value'].'" "';
  1582. }
  1583. echo
  1584. '# Microsoft Developer Studio Project File - Name="'.$this->name.'" - Package Owner=<4>
  1585. # Microsoft Developer Studio Generated Build File, Format Version 6.00
  1586. # ** DO NOT EDIT **
  1587. # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
  1588. CFG='.$this->name.' - Win32 Debug_TS
  1589. !MESSAGE This is not a valid makefile. To build this project using NMAKE,
  1590. !MESSAGE use the Export Makefile command and run
  1591. !MESSAGE
  1592. !MESSAGE NMAKE /f "'.$this->name.'.mak".
  1593. !MESSAGE
  1594. !MESSAGE You can specify a configuration when running NMAKE
  1595. !MESSAGE by defining the macro CFG on the command line. For example:
  1596. !MESSAGE
  1597. !MESSAGE NMAKE /f "'.$this->name.'.mak" CFG="'.$this->name.' - Win32 Debug_TS"
  1598. !MESSAGE
  1599. !MESSAGE Possible choices for configuration are:
  1600. !MESSAGE
  1601. !MESSAGE "'.$this->name.' - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
  1602. !MESSAGE "'.$this->name.' - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
  1603. !MESSAGE
  1604. # Begin Project
  1605. # PROP AllowPerConfigDependencies 0
  1606. # PROP Scc_ProjName ""
  1607. # PROP Scc_LocalPath ""
  1608. CPP=cl.exe
  1609. MTL=midl.exe
  1610. RSC=rc.exe
  1611. !IF "$(CFG)" == "'.$this->name.' - Win32 Release_TS"
  1612. # PROP BASE Use_MFC 0
  1613. # PROP BASE Use_Debug_Libraries 0
  1614. # PROP BASE Output_Dir "Release_TS"
  1615. # PROP BASE Intermediate_Dir "Release_TS"
  1616. # PROP BASE Target_Dir ""
  1617. # PROP Use_MFC 0
  1618. # PROP Use_Debug_Libraries 0
  1619. # PROP Output_Dir "Release_TS"
  1620. # PROP Intermediate_Dir "Release_TS"
  1621. # PROP Ignore_Export_Lib 0
  1622. # PROP Target_Dir ""
  1623. # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "'.strtoupper($this->name).'_EXPORTS" /YX /FD /c
  1624. # ADD CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\main" /D "WIN32" /D "PHP_EXPORTS" /D "COMPILE_DL_'.strtoupper($this->name).'" /D ZTS=1 '.$defines.' /D ZEND_DEBUG=0 /D "NDEBUG" /D "_WINDOWS" /D "ZEND_WIN32" /D "PHP_WIN32" /YX /FD /c
  1625. # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
  1626. # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
  1627. # ADD BASE RSC /l 0x407 /d "NDEBUG"
  1628. # ADD RSC /l 0x407 /d "NDEBUG"
  1629. BSC32=bscmake.exe
  1630. # ADD BASE BSC32 /nologo
  1631. # ADD BSC32 /nologo
  1632. LINK32=link.exe
  1633. # ADD BASE LINK32 '.$winlibs.' /nologo /dll /machine:I386
  1634. # ADD LINK32 php4ts.lib '.$winlibs.' /nologo /dll /machine:I386 /out:"..\..\Release_TS\php_'.$this->name.'.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline"
  1635. !ELSEIF "$(CFG)" == "'.$this->name.' - Win32 Debug_TS"
  1636. # PROP BASE Use_MFC 0
  1637. # PROP BASE Use_Debug_Libraries 1
  1638. # PROP BASE Output_Dir "Debug_TS"
  1639. # PROP BASE Intermediate_Dir "Debug_TS"
  1640. # PROP BASE Target_Dir ""
  1641. # PROP Use_MFC 0
  1642. # PROP Use_Debug_Libraries 1
  1643. # PROP Output_Dir "Debug_TS"
  1644. # PROP Intermediate_Dir "Debug_TS"
  1645. # PROP Ignore_Export_Lib 0
  1646. # PROP Target_Dir ""
  1647. # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "'.strtoupper($this->name).'_EXPORTS" /YX /FD /GZ /c
  1648. # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\main" /D ZEND_DEBUG=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "PHP_EXPORTS" /D "COMPILE_DL_'.strtoupper($this->name).'" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" '.$defines.' /YX /FD /GZ /c
  1649. # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
  1650. # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
  1651. # ADD BASE RSC /l 0x407 /d "_DEBUG"
  1652. # ADD RSC /l 0x407 /d "_DEBUG"
  1653. BSC32=bscmake.exe
  1654. # ADD BASE BSC32 /nologo
  1655. # ADD BSC32 /nologo
  1656. LINK32=link.exe
  1657. # ADD BASE LINK32 '.$winlibs.' /nologo /dll /debug /machine:I386 /pdbtype:sept
  1658. # ADD LINK32 php4ts_debug.lib '.$winlibs.' /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS\php_'.$this->name.'.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
  1659. !ENDIF
  1660. # Begin Target
  1661. # Name "'.$this->name.' - Win32 Release_TS"
  1662. # Name "'.$this->name.' - Win32 Debug_TS"
  1663. ';
  1664. echo '
  1665. # Begin Group "Source Files"
  1666. # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
  1667. ';
  1668. foreach ($this->packageFiles['code'] as $basename => $filepath) {
  1669. $filename = "./$basename";
  1670. echo "
  1671. # Begin Source File
  1672. SOURCE=$filename
  1673. # End Source File
  1674. ";
  1675. }
  1676. echo '
  1677. # End Group
  1678. ';
  1679. echo '
  1680. # Begin Group "Header Files"
  1681. # PROP Default_Filter "h;hpp;hxx;hm;inl"
  1682. ';
  1683. foreach ($this->packageFiles['header'] as $filename) {
  1684. if ($filename{0}!='/' && $filename{0}!='.') {
  1685. $filename = "./$filename";
  1686. }
  1687. $filename = str_replace("/","\\",$filename);
  1688. echo "
  1689. # Begin Source File
  1690. SOURCE=$filename
  1691. # End Source File
  1692. ";
  1693. }
  1694. echo
  1695. '# End Group
  1696. # End Target
  1697. # End Project
  1698. ';
  1699. return $file->write();
  1700. }
  1701. // }}}
  1702. /**
  1703. * Write authors to the CREDITS file
  1704. *
  1705. * @access private
  1706. * @param string directory to write to
  1707. */
  1708. function writeCredits()
  1709. {
  1710. if (count($this->authors)) {
  1711. $this->addPackageFile("doc", "CREDITS");
  1712. $fp = new CodeGen_Tools_FileReplacer($this->dirpath."/CREDITS");
  1713. $fp->puts("{$this->name}\n");
  1714. $names = array();
  1715. foreach ($this->authors as $author) {
  1716. $names[] = $author->getName();
  1717. }
  1718. $fp->puts(join(", ", $names) . "\n");
  1719. $fp->close();
  1720. }
  1721. }
  1722. /**
  1723. * Write EXPERIMENTAL file for non-stable extensions
  1724. *
  1725. * @access private
  1726. * @param string directory to write to
  1727. */
  1728. function writeExperimental()
  1729. {
  1730. if (($this->release) && $this->release->getState() === 'stable') {
  1731. return;
  1732. }
  1733. $this->addPackageFile("doc", "EXPERIMENTAL");
  1734. $fp = new CodeGen_Tools_FileReplacer($this->dirpath."/EXPERIMENTAL");
  1735. $fp->puts(
  1736. "this extension is experimental,
  1737. its functions may change their names
  1738. or move to extension all together
  1739. so do not rely to much on them
  1740. you have been warned!
  1741. ");
  1742. $fp->close();
  1743. }
  1744. /**
  1745. * Write file list for package.xml (both version 1.0 and 2.0)
  1746. *
  1747. * @return string
  1748. */
  1749. protected function packageXmlFileList()
  1750. {
  1751. $code = "";
  1752. $code.= " <dir name=\"/\">\n";
  1753. if (@is_array($this->packageFiles['doc'])) {
  1754. foreach ($this->packageFiles['doc'] as $file) {
  1755. $code.= " <file role='doc' name='$file'/>\n";
  1756. }
  1757. }
  1758. foreach (array("conf", "code", "header") as $type) {
  1759. foreach ($this->packageFiles[$type] as $basename => $filepath) {
  1760. $code.= " <file role='src' name='$basename'/>\n";
  1761. }
  1762. }
  1763. if (!empty($this->packageFiles['test'])) {
  1764. $code.= " <dir name=\"tests\">\n";
  1765. foreach ($this->packageFiles['test'] as $basename => $filepath) {
  1766. $code.= " <file role='test' name='$basename'/>\n";
  1767. }
  1768. $code.= " </dir>\n";
  1769. }
  1770. $code.= " </dir>\n";
  1771. return $code;
  1772. }
  1773. /**
  1774. * Write PEAR/PECL package.xml file
  1775. *
  1776. * @access private
  1777. * @param string directory to write to
  1778. */
  1779. function writePackageXml()
  1780. {
  1781. $outfile = new CodeGen_Tools_Outbuf($this->dirpath."/package.xml");
  1782. echo
  1783. "<?xml version=\"1.0\"?>
  1784. <!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\">
  1785. <package>
  1786. <name>{$this->name}</name>
  1787. ";
  1788. if (isset($this->summary)) {
  1789. echo " <summary>{$this->summary}</summary>\n";
  1790. }
  1791. if (isset($this->description)) {
  1792. echo " <description>\n".rtrim($this->description)."\n </description>\n";
  1793. }
  1794. if ($this->license) {
  1795. echo "\n <license>".$this->license->getShortName()."</license>\n";
  1796. }
  1797. if (count($this->with)) {
  1798. echo "\n <configureoptions>\n";
  1799. foreach ($this->with as $with) {
  1800. $configOption = "with-".$with->getName();
  1801. echo " <configureoption name=\"{$configOption}\" default=\"autodetect\" prompt=\"".$with->getName()." installation directory?\" />\n";
  1802. }
  1803. echo " </configureoptions>\n";
  1804. }
  1805. if (count($this->authors)) {
  1806. echo "\n <maintainers>\n";
  1807. foreach ($this->authors as $author) {
  1808. echo $author->packageXml();
  1809. }
  1810. echo " </maintainers>\n";
  1811. }
  1812. if (isset($this->release)) {
  1813. echo $this->release->packageXml();
  1814. }
  1815. echo " <changelog>\n";
  1816. echo $this->changelog."\n"; // TODO indent
  1817. echo " </changelog>\n";
  1818. echo " <deps>\n";
  1819. echo " <dep type=\"php\" rel=\"ge\" version=\"".$this->minPhpVersion()."\"/>\n";
  1820. echo $this->platform->packageXML();
  1821. foreach ($this->otherExtensions as $ext) {
  1822. echo $ext->packageXML();
  1823. }
  1824. echo " </deps>\n";
  1825. echo "\n <filelist>\n";
  1826. echo $this->packageXmlFileList();
  1827. echo " </filelist>\n";
  1828. echo "</package>\n";
  1829. return $outfile->write();
  1830. }
  1831. // }}}
  1832. /**
  1833. * Write PEAR/PECL package2.xml file
  1834. *
  1835. * @access private
  1836. * @param string directory to write to
  1837. */
  1838. function writePackageXml2()
  1839. {
  1840. $outfile = new CodeGen_Tools_Outbuf($this->dirpath."/package2.xml");
  1841. echo
  1842. '<?xml version="1.0"?>
  1843. <package version="2.0" xmlns="http://pear.php.net/dtd/package-2.0"
  1844. xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
  1845. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  1846. xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
  1847. http://pear.php.net/dtd/tasks-1.0.xsd
  1848. http://pear.php.net/dtd/package-2.0
  1849. http://pear.php.net/dtd/package-2.0.xsd">
  1850. ';
  1851. echo " <name>{$this->name}</name>\n";
  1852. echo " <channel>{$this->channel}</channel>\n\n";
  1853. if (isset($this->summary)) {
  1854. echo " <summary>{$this->summary}</summary>\n\n";
  1855. }
  1856. if (isset($this->description)) {
  1857. echo " <description>\n".rtrim($this->description)."\n </description>\n\n";
  1858. }
  1859. uasort($this->authors, array("CodeGen_PECL_Maintainer", "comp"));
  1860. foreach ($this->authors as $maintainer) {
  1861. echo $maintainer->packageXml2();
  1862. }
  1863. echo "\n";
  1864. echo $this->release->packageXml2($this->license);
  1865. echo " <contents>\n";
  1866. echo $this->packageXmlFileList();
  1867. echo " </contents>\n\n";
  1868. echo " <dependencies>\n";
  1869. echo " <required>\n";
  1870. echo " <php>\n";
  1871. echo " <min>".$this->minPhpVersion()."</min>\n";
  1872. echo " </php>\n";
  1873. echo " <pearinstaller>\n";
  1874. echo " <min>1.4.0a1</min>\n";
  1875. echo " </pearinstaller>\n";
  1876. foreach ($this->otherExtensions as $ext) {
  1877. echo $ext->packageXML2(array("REQUIRED", "CONFLICTS"));
  1878. }
  1879. echo $this->platform->packageXML2();
  1880. echo " </required>\n";
  1881. $optional = "";
  1882. foreach ($this->otherExtensions as $ext) {
  1883. $optional.= $ext->packageXML2(array("OPTIONAL"));
  1884. }
  1885. if (!empty($optional)) {
  1886. echo " <optional>\n";
  1887. echo $optional;
  1888. echo " </optional>\n";
  1889. }
  1890. echo " </dependencies>\n\n";
  1891. echo " <providesextension>{$this->name}</providesextension>\n\n";
  1892. if (count($this->with)) {
  1893. echo " <extsrcrelease>\n";
  1894. foreach ($this->with as $with) {
  1895. $configOption = "with-".$with->getName();
  1896. echo " <configureoption name=\"{$configOption}\" default=\"autodetect\" prompt=\"".$with->getName()." installation directory?\" />\n";
  1897. }
  1898. echo " </extsrcrelease>\n\n";
  1899. } else {
  1900. echo " <extsrcrelease/>\n\n";
  1901. }
  1902. echo "</package>\n";
  1903. return $outfile->write();
  1904. }
  1905. // }}}
  1906. /**
  1907. * add a custom test case
  1908. *
  1909. * @access public
  1910. * @param object a Test object
  1911. */
  1912. function addTest(CodeGen_PECL_Element_Test $test)
  1913. {
  1914. $name = $test->getName();
  1915. if (isset($this->testcases[$name])) {
  1916. return PEAR::raiseError("testcase '{$name}' added twice");
  1917. }
  1918. $this->testcases[$name] = $test;
  1919. return true;
  1920. }
  1921. /**
  1922. * Write test case files
  1923. *
  1924. * @access private
  1925. */
  1926. function writeTestFiles()
  1927. {
  1928. $testCount=0;
  1929. @mkdir($this->dirpath."/tests");
  1930. // function related tests
  1931. foreach ($this->functions as $function) {
  1932. $function->writeTest($this);
  1933. }
  1934. // class method related tests
  1935. foreach ($this->classes as $class) {
  1936. $class->writeTests($this);
  1937. }
  1938. // custom test cases (may overwrite custom function test cases)
  1939. foreach ($this->testcases as $test) {
  1940. $test->writeTest($this);
  1941. }
  1942. if (0 == count(glob($this->dirpath."/tests/*.phpt"))) {
  1943. rmdir($this->dirpath."/tests");
  1944. }
  1945. }
  1946. /**
  1947. * Generate README file (custom or default)
  1948. *
  1949. * @access private
  1950. * @param string directory to write to
  1951. */
  1952. function writeReadme()
  1953. {
  1954. $file = new CodeGen_Tools_Outbuf($this->dirpath."/README");
  1955. $configOption = "";
  1956. if (count($this->with)) {
  1957. foreach ($this->with as $with) {
  1958. $configOption.= "[--with-".$with->getName()."=...] ";
  1959. }
  1960. } else {
  1961. $configOption.= "[--enable--".$this->name."] ";
  1962. }
  1963. ?>
  1964. This is a standalone PHP extension created using CodeGen_PECL <?php echo self::version(); ?>
  1965. HACKING
  1966. =======
  1967. There are two ways to modify an extension created using CodeGen_PECL:
  1968. 1) you can modify the generated code as with any other PHP extension
  1969. 2) you can add custom code to the CodeGen_PECL XML source and re-run pecl-gen
  1970. The 2nd approach may look a bit complicated but you have be aware that any
  1971. manual changes to the generated code will be lost if you ever change the
  1972. XML specs and re-run PECL-Gen. All changes done before have to be applied
  1973. to the newly generated code again.
  1974. Adding code snippets to the XML source itself on the other hand may be a
  1975. bit more complicated but this way your custom code will always be in the
  1976. generated code no matter how often you rerun CodeGen_PECL.
  1977. <?php if ($this->platform->test("unix")): ?>
  1978. BUILDING ON UNIX etc.
  1979. =====================
  1980. To compile your new extension, you will have to execute the following steps:
  1981. 1. $ ./phpize
  1982. 2. $ ./configure <?php echo $configOption."\n"; ?>
  1983. 3. $ make
  1984. 4. $ make test
  1985. 5. $ [sudo] make install
  1986. <?php endif; ?>
  1987. <?php if ($this->platform->test("windows")): ?>
  1988. BUILDING ON WINDOWS
  1989. ===================
  1990. The extension provides the VisualStudio V6 project file
  1991. <?php echo $this->name.".dsp" ?>
  1992. To compile the extension you open this file using VisualStudio,
  1993. select the apropriate configuration for your installation
  1994. (either "Release_TS" or "Debug_TS") and create "php_<?php echo $this->name; ?>.dll"
  1995. After successfull compilation you have to copy the newly
  1996. created "<?php echo $this->name; ?>.dll" to the PHP
  1997. extension directory (default: C:\PHP\extensions).
  1998. <?php endif; ?>
  1999. TESTING
  2000. =======
  2001. You can now load the extension using a php.ini directive
  2002. extension="<?php echo $this->name; ?>.[so|dll]"
  2003. or load it at runtime using the dl() function
  2004. dl("<?php echo $this->name; ?>.[so|dll]");
  2005. The extension should now be available, you can test this
  2006. using the extension_loaded() function:
  2007. if (extension_loaded("<?php echo $this->name; ?>"))
  2008. echo "<?php echo $this->name; ?> loaded :)";
  2009. else
  2010. echo "something is wrong :(";
  2011. The extension will also add its own block to the output
  2012. of phpinfo();
  2013. <?php
  2014. $file->write();
  2015. }
  2016. /**
  2017. * Return minimal PHP version required to support the requested features
  2018. *
  2019. * @return string version string
  2020. */
  2021. function minPhpVersion()
  2022. {
  2023. // min. default: 4.0
  2024. $version = "4.0.0"; // TODO test for real lower bound
  2025. // we only support the 5.0 (ZE2) OO api
  2026. if (!empty($this->classes) || !empty($this->interfaces)) {
  2027. $version = $this->maxVersion($version, "5.0.0");
  2028. }
  2029. // extension interdependencies only exist in 5.1 and above
  2030. if (!empty($this->otherExtensions)) {
  2031. $version = $this->maxVersion($version, "5.1.0rc1");
  2032. }
  2033. // check function requirements
  2034. foreach ($this->functions as $function) {
  2035. $version = $this->maxVersion($version, $function->minPhpVersion());
  2036. }
  2037. // check class requirements
  2038. foreach ($this->classes as $class) {
  2039. $version = $this->maxVersion($version, $class->minPhpVersion());
  2040. }
  2041. // check interface requirements
  2042. foreach ($this->interfaces as $interface) {
  2043. $version = $this->maxVersion($version, $interface->minPhpVersion());
  2044. }
  2045. return $version;
  2046. }
  2047. function maxVersion($v1, $v2)
  2048. {
  2049. return version_compare($v1, $v2) > 0 ? $v1 : $v2;
  2050. }
  2051. /**
  2052. * Return minimal PHP version required to support the requested features
  2053. *
  2054. * @return string version string
  2055. */
  2056. function minPhpVersionId()
  2057. {
  2058. $id = explode('.', $this->minPhpVersion());
  2059. return (int)$id[0] * 10000 + (int)$id[1] * 100 + (int)$id[2];
  2060. }
  2061. /**
  2062. * Generate Editor settings block for documentation files
  2063. *
  2064. * @access public
  2065. * @param int Directory nesting depth of target file (default: 3)
  2066. * @return string Editor settings comment block
  2067. */
  2068. static function docEditorSettings($level=3)
  2069. {
  2070. return '
  2071. <!-- Keep this comment at the end of the file
  2072. Local'.' variables:
  2073. mode: sgml
  2074. sgml-omittag:t
  2075. sgml-shorttag:t
  2076. sgml-minimize-attributes:nil
  2077. sgml-always-quote-attributes:t
  2078. sgml-indent-step:1
  2079. sgml-indent-data:t
  2080. indent-tabs-mode:nil
  2081. sgml-parent-document:nil
  2082. sgml-default-dtd-file:"'.str_repeat("../", $level).'manual.ced"
  2083. sgml-exposed-tags:nil
  2084. sgml-local-catalogs:nil
  2085. sgml-local-ecat-files:nil
  2086. End:
  2087. vim600: syn=xml fen fdm=syntax fdl=2 si
  2088. vim: et tw=78 syn=sgml
  2089. vi: ts=1 sw=1
  2090. -->
  2091. ';
  2092. }
  2093. /**
  2094. * Show error message and bailout
  2095. *
  2096. * @param string error message
  2097. */
  2098. function terminate($msg)
  2099. {
  2100. while (@ob_end_clean()); // purge output buffers
  2101. $stderr = fopen("php://stderr", "w");
  2102. if ($stderr) {
  2103. fprintf($stderr, "%s\n", $msg);
  2104. fclose($stderr);
  2105. } else {
  2106. echo "$msg\n";
  2107. }
  2108. exit(3);
  2109. }
  2110. /**
  2111. * Return array of defined functions
  2112. *
  2113. * @return array
  2114. */
  2115. function getFunctions()
  2116. {
  2117. return $this->functions;
  2118. }
  2119. }
  2120. /*
  2121. * Local variables:
  2122. * tab-width: 4
  2123. * c-basic-offset: 4
  2124. * indent-tabs-mode:nil
  2125. * End:
  2126. */