summaryrefslogtreecommitdiff
path: root/buildscripts/phing/classes/phing/types/Commandline.php
diff options
context:
space:
mode:
Diffstat (limited to 'buildscripts/phing/classes/phing/types/Commandline.php')
-rw-r--r--buildscripts/phing/classes/phing/types/Commandline.php467
1 files changed, 467 insertions, 0 deletions
diff --git a/buildscripts/phing/classes/phing/types/Commandline.php b/buildscripts/phing/classes/phing/types/Commandline.php
new file mode 100644
index 00000000..877179d0
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Commandline.php
@@ -0,0 +1,467 @@
+<?php
+/*
+ * $Id: Commandline.php,v 1.11 2005/05/26 13:10:53 mrook Exp $
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the LGPL. For more information please see
+ * <http://phing.info>.
+ */
+
+
+/**
+ * Commandline objects help handling command lines specifying processes to
+ * execute.
+ *
+ * The class can be used to define a command line as nested elements or as a
+ * helper to define a command line by an application.
+ * <p>
+ * <code>
+ * &lt;someelement&gt;<br>
+ * &nbsp;&nbsp;&lt;acommandline executable="/executable/to/run"&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 1" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument line="argument_1 argument_2 argument_3" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 4" /&gt;<br>
+ * &nbsp;&nbsp;&lt;/acommandline&gt;<br>
+ * &lt;/someelement&gt;<br>
+ * </code>
+ * The element <code>someelement</code> must provide a method
+ * <code>createAcommandline</code> which returns an instance of this class.
+ *
+ * @author thomas.haas@softwired-inc.com
+ * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
+ */
+class Commandline {
+
+ /**
+ * @var array CommandlineArguments[]
+ */
+ public $arguments = array(); // public so "inner" class can access
+
+ /**
+ * Full path (if not on %PATH% env var) to executable program.
+ * @var string
+ */
+ public $executable; // public so "inner" class can access
+
+ const DISCLAIMER = "The ' characters around the executable and arguments are not part of the command.";
+
+ public function __construct($to_process = null) {
+ if ($to_process !== null) {
+ $tmp = $this->translateCommandline($to_process);
+ if ($tmp) {
+ $this->setExecutable(array_shift($tmp)); // removes first el
+ foreach($tmp as $arg) { // iterate through remaining elements
+ $this->createArgument()->setValue($arg);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Creates an argument object and adds it to our list of args.
+ *
+ * <p>Each commandline object has at most one instance of the
+ * argument class.</p>
+ *
+ * @param boolean $insertAtStart if true, the argument is inserted at the
+ * beginning of the list of args, otherwise it is appended.
+ * @return CommandlineArgument
+ */
+ public function createArgument($insertAtStart = false) {
+ $argument = new CommandlineArgument($this);
+ if ($insertAtStart) {
+ array_unshift($this->arguments, $argument);
+ } else {
+ array_push($this->arguments, $argument);
+ }
+ return $argument;
+ }
+
+ /**
+ * Sets the executable to run.
+ */
+ public function setExecutable($executable) {
+ if (!$executable) {
+ return;
+ }
+ $this->executable = $executable;
+ $this->executable = strtr($this->executable, '/', DIRECTORY_SEPARATOR);
+ $this->executable = strtr($this->executable, '\\', DIRECTORY_SEPARATOR);
+ }
+
+ public function getExecutable() {
+ return $this->executable;
+ }
+
+ public function addArguments($line) {
+ foreach($line as $arg) {
+ $this->createArgument()->setValue($arg);
+ }
+ }
+
+ /**
+ * Returns the executable and all defined arguments.
+ * @return array
+ */
+ public function getCommandline() {
+ $args = $this->getArguments();
+ if ($this->executable === null) {
+ return $args;
+ }
+ return array_merge(array($this->executable), $args);
+ }
+
+
+ /**
+ * Returns all arguments defined by <code>addLine</code>,
+ * <code>addValue</code> or the argument object.
+ */
+ public function getArguments() {
+ $result = array();
+ foreach($this->arguments as $arg) {
+ $parts = $arg->getParts();
+ if ($parts !== null) {
+ foreach($parts as $part) {
+ $result[] = $part;
+ }
+ }
+ }
+ return $result;
+ }
+
+ public function __toString() {
+ return self::toString($this->getCommandline());
+ }
+
+ /**
+ * Put quotes around the given String if necessary.
+ *
+ * <p>If the argument doesn't include spaces or quotes, return it
+ * as is. If it contains double quotes, use single quotes - else
+ * surround the argument by double quotes.</p>
+ *
+ * @exception BuildException if the argument contains both, single
+ * and double quotes.
+ */
+ public static function quoteArgument($argument) {
+ if (strpos($argument, "\"") !== false) {
+ if (strpos($argument, "'") !== false) {
+ throw new BuildException("Can't handle single and double quotes in same argument");
+ } else {
+ return escapeshellarg($argument);
+ }
+ } elseif (strpos($argument, "'") !== false || strpos($argument, " ") !== false) {
+ return escapeshellarg($argument);
+ //return '\"' . $argument . '\"';
+ } else {
+ return $argument;
+ }
+ }
+
+ /**
+ * Quotes the parts of the given array in way that makes them
+ * usable as command line arguments.
+ */
+ public static function toString($lines) {
+ // empty path return empty string
+ if (!$lines) {
+ return "";
+ }
+
+ // path containing one or more elements
+ $result = "";
+ for ($i = 0, $len=count($lines); $i < $len; $i++) {
+ if ($i > 0) {
+ $result .= ' ';
+ }
+ $result .= self::quoteArgument($lines[$i]);
+ }
+ return $result;
+ }
+
+ /**
+ *
+ * @param string $to_process
+ * @return array
+ */
+ public static function translateCommandline($to_process) {
+
+ if (!$to_process) {
+ return array();
+ }
+
+ // parse with a simple finite state machine
+
+ $normal = 0;
+ $inQuote = 1;
+ $inDoubleQuote = 2;
+
+ $state = $normal;
+ $args = array();
+ $current = "";
+ $lastTokenHasBeenQuoted = false;
+
+ $tok = strtok($to_process, "");
+ $tokens = preg_split('/(["\' ])/', $to_process, -1, PREG_SPLIT_DELIM_CAPTURE);
+ while(($nextTok = array_shift($tokens)) !== null) {
+ switch ($state) {
+ case $inQuote:
+ if ("'" == $nextTok) {
+ $lastTokenHasBeenQuoted = true;
+ $state = $normal;
+ } else {
+ $current .= $nextTok;
+ }
+ break;
+ case $inDoubleQuote:
+ if ("\"" == $nextTok) {
+ $lastTokenHasBeenQuoted = true;
+ $state = $normal;
+ } else {
+ $current .= $nextTok;
+ }
+ break;
+ default:
+ if ("'" == $nextTok) {
+ $state = $inQuote;
+ } elseif ("\"" == $nextTok) {
+ $state = $inDoubleQuote;
+ } elseif (" " == $nextTok) {
+ if ($lastTokenHasBeenQuoted || strlen($current) != 0) {
+ $args[] = $current;
+ $current = "";
+ }
+ } else {
+ $current .= $nextTok;
+ }
+ $lastTokenHasBeenQuoted = false;
+ break;
+ }
+ }
+
+ if ($lastTokenHasBeenQuoted || strlen($current) != 0) {
+ $args[] = $current;
+ }
+
+ if ($state == $inQuote || $state == $inDoubleQuote) {
+ throw new BuildException("unbalanced quotes in " . $to_process);
+ }
+
+ return $args;
+ }
+
+ /**
+ * @return int Number of components in current commandline.
+ */
+ public function size() {
+ return count($this->getCommandline());
+ }
+
+ public function __copy() {
+ $c = new Commandline();
+ $c->setExecutable($this->executable);
+ $c->addArguments($this->getArguments());
+ return $c;
+ }
+
+ /**
+ * Clear out the whole command line. */
+ public function clear() {
+ $this->executable = null;
+ $this->arguments->removeAllElements();
+ }
+
+ /**
+ * Clear out the arguments but leave the executable in place for
+ * another operation.
+ */
+ public function clearArgs() {
+ $this->arguments = array();
+ }
+
+ /**
+ * Return a marker.
+ *
+ * <p>This marker can be used to locate a position on the
+ * commandline - to insert something for example - when all
+ * parameters have been set.</p>
+ * @return CommandlineMarker
+ */
+ public function createMarker() {
+ return new CommandlineMarker($this, count($this->arguments));
+ }
+
+ /**
+ * Returns a String that describes the command and arguments
+ * suitable for verbose output before a call to
+ * <code>Runtime.exec(String[])<code>.
+ *
+ * <p>This method assumes that the first entry in the array is the
+ * executable to run.</p>
+ * @param array $args CommandlineArgument[] to use
+ * @return string
+ */
+ public function describeCommand($args = null) {
+
+ if ($args === null) {
+ $args = $this->getCommandline();
+ }
+
+ if (!$args) {
+ return "";
+ }
+
+ $buf = "Executing '";
+ $buf .= $args[0];
+ $buf .= "'";
+ if (count($args) > 0) {
+ $buf .= " with ";
+ $buf .= $this->describeArguments($args, 1);
+ } else {
+ $buf .= self::DISCLAIMER;
+ }
+ return $buf;
+ }
+
+ /**
+ * Returns a String that describes the arguments suitable for
+ * verbose output before a call to
+ * <code>Runtime.exec(String[])<code>
+ * @param $args arguments to use (default is to use current class args)
+ * @param $offset ignore entries before this index
+ * @return string
+ */
+ protected function describeArguments($args = null, $offset = 0) {
+ if ($args === null) {
+ $args = $this->getArguments();
+ }
+
+ if ($args === null || count($args) <= $offset) {
+ return "";
+ }
+
+ $buf = "argument";
+ if (count($args) > $offset) {
+ $buf .= "s";
+ }
+ $buf .= ":" . Phing::getProperty("line.separator");
+ for ($i = $offset, $alen=count($args); $i < $alen; $i++) {
+ $buf .= "'" . $args[$i] . "'" . Phing::getProperty("line.separator");
+ }
+ $buf .= self::DISCLAIMER;
+ return $buf;
+ }
+}
+
+
+/**
+ * "Inner" class used for nested xml command line definitions.
+ */
+class CommandlineArgument {
+
+ private $parts = array();
+ private $outer;
+
+ public function __construct(Commandline $outer) {
+ $this->outer = $outer;
+ }
+
+ /**
+ * Sets a single commandline argument.
+ *
+ * @param string $value a single commandline argument.
+ */
+ public function setValue($value) {
+ $this->parts = array($value);
+ }
+
+ /**
+ * Line to split into several commandline arguments.
+ *
+ * @param line line to split into several commandline arguments
+ */
+ public function setLine($line) {
+ if ($line === null) {
+ return;
+ }
+ $this->parts = $this->outer->translateCommandline($line);
+ }
+
+ /**
+ * Sets a single commandline argument and treats it like a
+ * PATH - ensures the right separator for the local platform
+ * is used.
+ *
+ * @param value a single commandline argument.
+ */
+ public function setPath($value) {
+ $this->parts = array( (string) $value );
+ }
+
+ /**
+ * Sets a single commandline argument to the absolute filename
+ * of the given file.
+ *
+ * @param value a single commandline argument.
+ */
+ public function setFile(PhingFile $value) {
+ $this->parts = array($value->getAbsolutePath());
+ }
+
+ /**
+ * Returns the parts this Argument consists of.
+ * @return array string[]
+ */
+ public function getParts() {
+ return $this->parts;
+ }
+}
+
+/**
+ * Class to keep track of the position of an Argument.
+ */
+// <p>This class is there to support the srcfile and targetfile
+// elements of &lt;execon&gt; and &lt;transform&gt; - don't know
+// whether there might be additional use cases.</p> --SB
+class CommandlineMarker {
+
+ private $position;
+ private $realPos = -1;
+ private $outer;
+
+ public function __construct(Comandline $outer, $position) {
+ $this->outer = $outer;
+ $this->position = $position;
+ }
+
+ /**
+ * Return the number of arguments that preceeded this marker.
+ *
+ * <p>The name of the executable - if set - is counted as the
+ * very first argument.</p>
+ */
+ public function getPosition() {
+ if ($this->realPos == -1) {
+ $realPos = ($this->outer->executable === null ? 0 : 1);
+ for ($i = 0; $i < $position; $i++) {
+ $arg = $this->arguments[$i];
+ $realPos += count($arg->getParts());
+ }
+ }
+ return $this->realPos;
+ }
+}
+