#!/usr/bin/php -Cq
<?php

/**
* Console script to generate PECL extensions from command line
*
* @author Hartmut Holzgraefe <hartmut@php.net>
* @version $Id: pecl-gen,v 1.4 2004/11/11 15:34:50 hholzgra Exp $
*/

// includes
require_once 'PEAR.php';
require_once "PECL/Gen/Extension.php";
require_once "PECL/Gen/ExtensionParser.php";
require_once "PECL/Gen/Element.php";
require_once "PECL/Gen/Tools/Getopt.php";

// no compromise
error_reporting(E_ALL);

// but make sure errors are written to stderr so they can't be collected by ob_* functions
function errors_to_stderr($errno, $errstr, $errfile, $errline) {
	if ($errno & error_reporting()) {
		$fp = fopen("php://stderr", "w");
		
		switch ($errno) {
		case E_ERROR           : fputs($fp, "Error"); break;
		case E_WARNING         : fputs($fp, "Warning"); break;
		case E_PARSE           : fputs($fp, "Parsing Error"); break;
		case E_NOTICE          : fputs($fp, "Notice"); break;
		case E_CORE_ERROR      : fputs($fp, "Core Error"); break;
		case E_CORE_WARNING    : fputs($fp, "Core Warning"); break;
		case E_COMPILE_ERROR   : fputs($fp, "Compile Error"); break;
		case E_COMPILE_WARNING : fputs($fp, "Compile Warning"); break;
		case E_USER_ERROR      : fputs($fp, "User Error"); break;
		case E_USER_WARNING    : fputs($fp, "User Warning"); break;
		case E_USER_NOTICE     : fputs($fp, "User Notice"); break;
		case E_STRICT          : fputs($fp, "Runtime Notice"); break;
		default                : fputs($fp, "Unknown Error"); break;
		}
		
		fputs($fp, ": $errstr in $errfile on line $errline\n");
		fclose($fp);
	}
}
set_error_handler("errors_to_stderr");

// bailout function
function terminate($msg) {
	$stderr = fopen("php://stderr/", "w");
	if ($stderr) {
		fprintf($stderr, "%s\n", $msg);
		fclose($stderr);
	} else {
		echo "$msg\n";
    }
	exit(3);
}

// create extension object
$extension = new PECL_Gen_Extension;

$options = new PECL_Gen_Tools_Getopt("fhq", 
									 array( "help",  
											"extname=", 
											"force",
											"full-xml", 
											"function=",
											"no-help",
											"proto=",
											"quiet", 
											"skel="    , 
											"stubs=",  
											"version", 
											"xml==", 
											),
									 "usage");
    
if ($options->have("help", "h")) {
	version();
	usage();
	exit(0);
}

if ($options->have("version")) {
    version();
    exit(0);
}

// ext_skel compatibility?
if ($options->have("extname")) {
    $ext = new PECL_Gen_Extension;

    $extname = $options->value("extname");
    
    $err = $ext->set_name($extname);
    if (PEAR::isError($err)) {
        terminate($err->get_message());
    }

    if ($options->have("proto")) {
		$proto_file = $options->value("proto");
		
		if (!file_exists($proto_file) || !is_readable($proto_file)) {
			terminate("cannot open proto file");  
        }
		
        foreach (file($proto_file) as $line) {
            $func = new PECL_Gen_Element_Function;
            $func->set_role("public");
            $err = $func->set_proto(trim($line));
            if (PEAR::isError($err)) {
                terminate($err->get_message());
            }   
            
            $err = $ext->add_function($func);
            if (PEAR::isError($err)) {
                terminate($err->get_message());
            }
        }
    }
	
    if ($options->have("stubs")) {
        $stubname = $options->value("stubs");
		
        if (file_exists("$stubname")  && !$options->have("f", "force")) {
            terminate("'$stubname' already exists (use '--force' to overwrite)"); 
        }
		
        $fp = fopen($stubname, "w");
        fputs($fp, $ext->public_functions_c());
        
        fputs($fp, "\n\n/*----------------------------------------------------------------------*/\n\n");
		
        foreach ($ext->functions as $name => $function) {
            fputs($fp, sprintf("\tPHP_FE(%-20s, NULL)\n",$name));
        }
		
        fputs($fp, "\n\n/*----------------------------------------------------------------------*/\n\n");
		
        foreach ($ext->functions as $name => $function) {
            fputs($fp, "PHP_FUNCTION($name);\n");
        }
		
        fclose($fp);
		
        echo "$stubname successfully written\n";
    } else { 
        if (file_exists("./$extname")  && !$options->have("f", "force")) {
            terminate("'$extname' already exists, can't create directory (use '--force' to override)"); 
        }
        
        $err = System::mkdir($extname);
        if (PEAR::isError($err)) {
            terminate($err->get_message());
        }
        
        $err = $ext->generate_source("./$extname");
        if (PEAR::isError($err)) {
            terminate($err->get_message());
        }
        
        if ($options->have("xml")) {
            $manpath = "$extname/manual/". str_replace('_', '-', $extname);
            
            $err = System::mkdir("-p $manpath");
            if (PEAR::isError($err)) {
                terminate($err->get_message());
            }
            
            $err = $ext->generate_documentation($manpath);
            if (PEAR::isError($err)) {
                terminate($err->get_message());
            }
        }

      $ext->write_readme("./$extname");

        if (!$options->have("quiet")) {
            echo $ext->success_msg($extname);
        }
    }

    exit(0);
}


if ($options->have("function"))
{
    $ext = new PECL_Gen_Extension;

    $func = new PECL_Gen_Element_Function;
    $func->set_role("public");
    $err = $func->set_proto(trim($options->value("function")));
    if (PEAR::isError($err)) {
        terminate($err->get_message());
    }   

    $err = $ext->add_function($func);
    if (PEAR::isError($err)) {
        terminate($err->get_message());
    }

    echo $ext->public_functions_c();
    
    echo "\n\n/*----------------------------------------------------------------------*/\n\n";

    foreach ($ext->functions as $name => $function) {
        echo sprintf("\tPHP_FE(%-20s, NULL)\n",$name);
    }

    echo "\n\n/*----------------------------------------------------------------------*/\n\n";

    foreach ($ext->functions as $name => $function) {
        echo "PHP_FUNCTION($name);\n";
    }

    exit(0);
}



// normal operation: read XML file and go with that
$arguments = $options->arguments();
if (count($arguments) != 1) {
    usage();
    exit(3);
}

$xmlfile = $arguments[0];

if (!file_exists($xmlfile) || !is_readable($xmlfile)) {
    terminate("Cannot open XML spec file '$xmlfile'");
}

// create XML parser for extension specs
$parser    = new PECL_Gen_ExtensionParser($extension);
$err = $parser->setInputFile($xmlfile);
if (PEAR::isError($err)) {
    terminate($err->message);
}

// do the actual parsing
$err = $parser->parse();
if (PEAR::isError($err)) {
    terminate($err->getMessage()." ".$err->getUserInfo());
}

// and now create the actual PECL extension dir from the collected specs
$err = $extension->create_extension(".", $options->have("f", "force"));
if (PEAR::isError($err)) {
    terminate($err->getMessage()." ".$err->getUserInfo());
}

if (!$options->have("quiet")) {
  echo $extension->success_msg($extension->name);
}

exit(0);






function version()
{
    $fp = fopen("php://stderr", "w");
    fputs($fp, "pecl-gen ". PECL_Gen_Extension::version() . ", Copyright (c) 2003, 2004 The PHP Group\n");
    fclose($fp);
}

function usage($message = false)
{
    $fp = fopen("php://stderr", "w");

    if ($message) fputs($fp, "$message\n\n");

    fputs($fp, "Usage:

pecl-gen [-h] [--extname=name] [--proto=file] [--skel=dir] [--stubs=file] 
  [--no-help] [--xml[=file]] [--full-xml] [--function=proto] [specfile.xml]

  -h|--help          this message
  --force            overwrite existing directories
  --function         create a function skeleton from a proto right away
  --version          show version info

  the following options are inherited from ext_skel:

  --extname=module   module is the name of your extension 
  --proto=file       file contains prototypes of functions to create
  --xml              generate xml documentation to be added to phpdoc-cvs

  these wait for functionality to be implemented and are ignored for now ...
  --stubs=file       generate only function stubs in file
  --no-help          don't try to be nice and create comments in the code
                     and helper functions to test if the module compiled

  these are accepted for backwards compatibility reasons but not used ...
  --full-xml         generate xml documentation for a self-contained extension
                     (this was also a no-op in ext_skel) 
  --skel=dir         path to the skeleton directory
                     (skeleton stuff is now self-contained)
");

    fclose($fp);
}

?>
