Compare commits
7 Commits
ecc0239106
...
42766d07a5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42766d07a5 | ||
|
|
ffd75a57d4 | ||
|
|
c4031b71f8 | ||
| 5ff8278ad0 | |||
|
|
3eaffe64f9 | ||
|
|
3b5a291de9 | ||
|
|
f474a92a13 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@
|
|||||||
/flags
|
/flags
|
||||||
/test
|
/test
|
||||||
tags
|
tags
|
||||||
|
.php-cs-fixer.cache
|
||||||
|
|||||||
@@ -89,13 +89,13 @@ class Console
|
|||||||
{
|
{
|
||||||
if (! function_exists ("exec"))
|
if (! function_exists ("exec"))
|
||||||
throw $this->ConsoleException ("No exec support in PHP");
|
throw $this->ConsoleException ("No exec support in PHP");
|
||||||
$this->initSttyState = exec ("stty -g");
|
$this->initSttyState = exec ("stty -g 2>/dev/null");
|
||||||
// Set the terminal to return the value each time a key is pressed.
|
// Set the terminal to return the value each time a key is pressed.
|
||||||
// Do not display anything, so we don't see the characters when the user is
|
// Do not display anything, so we don't see the characters when the user is
|
||||||
// deleting.
|
// deleting.
|
||||||
// 'intr ^J' allow to redefine the interruption from Ctrl+C to Ctrl+J. It
|
// 'intr ^J' allow to redefine the interruption from Ctrl+C to Ctrl+J. It
|
||||||
// allow to manage the Ctrl+C key to clean the entry
|
// allow to manage the Ctrl+C key to clean the entry
|
||||||
exec ("stty -echo -icanon min 1 time 0");
|
exec ("stty -echo -icanon min 1 time 0 2>/dev/null");
|
||||||
$this->updateTerminalSize ();
|
$this->updateTerminalSize ();
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
@@ -107,7 +107,7 @@ class Console
|
|||||||
{
|
{
|
||||||
$this->termWidth = 80;
|
$this->termWidth = 80;
|
||||||
$this->termHeight = 25;
|
$this->termHeight = 25;
|
||||||
$termSize = exec ("stty size", $null, $rc);
|
$termSize = exec ("stty size 2>/dev/null", $null, $rc);
|
||||||
if ($rc === 0)
|
if ($rc === 0)
|
||||||
{
|
{
|
||||||
list ($termHeight, $termWidth) = explode (" ", $termSize);
|
list ($termHeight, $termWidth) = explode (" ", $termSize);
|
||||||
@@ -128,7 +128,8 @@ class Console
|
|||||||
public function __destruct ()
|
public function __destruct ()
|
||||||
// {{{
|
// {{{
|
||||||
{
|
{
|
||||||
exec ("stty $this->initSttyState");
|
if ($this->initSttyState !== "")
|
||||||
|
exec ("stty $this->initSttyState");
|
||||||
$this->colorReset ();
|
$this->colorReset ();
|
||||||
$this->textUnderline (false);
|
$this->textUnderline (false);
|
||||||
$this->textBold (false);
|
$this->textBold (false);
|
||||||
@@ -207,7 +208,7 @@ class Console
|
|||||||
$char = fgetc (STDIN);
|
$char = fgetc (STDIN);
|
||||||
$sequence .= $char;
|
$sequence .= $char;
|
||||||
}
|
}
|
||||||
elseif (ord ($char2) === 91)
|
elseif (ord ($char2) === 91 || ord($char2) === 93)
|
||||||
{
|
{
|
||||||
// Start an ESC CSI sequence. Do not display it, just return it.
|
// Start an ESC CSI sequence. Do not display it, just return it.
|
||||||
// The ESC squences are used to communicate the cursor keys, associated
|
// The ESC squences are used to communicate the cursor keys, associated
|
||||||
@@ -412,6 +413,13 @@ class Console
|
|||||||
$this->debug ("Autocompletion : end '$prompt.$string'");
|
$this->debug ("Autocompletion : end '$prompt.$string'");
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
elseif (ord ($char) === 0)
|
||||||
|
// End of file
|
||||||
|
{
|
||||||
|
$this->debug("Empty File entry : ".ord($char));
|
||||||
|
$string = chr(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
elseif (ord ($char) === 3)
|
elseif (ord ($char) === 3)
|
||||||
// Abort (Ctrl+C)
|
// Abort (Ctrl+C)
|
||||||
// {{{
|
// {{{
|
||||||
@@ -473,7 +481,7 @@ class Console
|
|||||||
$this->moveCursor ($cursorPos);
|
$this->moveCursor ($cursorPos);
|
||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
elseif (ord($char) === 127)
|
elseif (ord($char) === 127 || ord($char) === 8)
|
||||||
// Remove the previous char (Backspace)
|
// Remove the previous char (Backspace)
|
||||||
// {{{
|
// {{{
|
||||||
{
|
{
|
||||||
@@ -985,6 +993,13 @@ class Console
|
|||||||
}
|
}
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
/** Return true if the TTY is enabled, or false if the program is called from pipe
|
||||||
|
*/
|
||||||
|
public function isTTY()
|
||||||
|
{
|
||||||
|
return !! $this->initSttyState;
|
||||||
|
}
|
||||||
|
|
||||||
/** Tokenize the provided line and aggragate if there is single or double
|
/** Tokenize the provided line and aggragate if there is single or double
|
||||||
* quotes.
|
* quotes.
|
||||||
* Trim the spaces
|
* Trim the spaces
|
||||||
|
|||||||
@@ -507,6 +507,7 @@ class File
|
|||||||
{
|
{
|
||||||
$res = flock ($this->locks[$filename], LOCK_UN);
|
$res = flock ($this->locks[$filename], LOCK_UN);
|
||||||
fclose ($this->locks[$filename]);
|
fclose ($this->locks[$filename]);
|
||||||
|
unset($this->locks[$filename]);
|
||||||
}
|
}
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ class Rest
|
|||||||
$text = $http->codetext ($code);
|
$text = $http->codetext ($code);
|
||||||
header ($_SERVER["SERVER_PROTOCOL"]." $code $text");
|
header ($_SERVER["SERVER_PROTOCOL"]." $code $text");
|
||||||
$type = $this->chooseType ();
|
$type = $this->chooseType ();
|
||||||
require_once ("domframework/output$type.php");
|
|
||||||
$constr = __NAMESPACE__."\\Output$type";
|
$constr = __NAMESPACE__."\\Output$type";
|
||||||
$method = "out";
|
$method = "out";
|
||||||
$obj = new $constr ();
|
$obj = new $constr ();
|
||||||
|
|||||||
131
src/StateMachine.php
Normal file
131
src/StateMachine.php
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
/** DomFramework
|
||||||
|
* @package domframework
|
||||||
|
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||||
|
* @license BSD
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Domframework;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class manage a state machine.
|
||||||
|
* Define the states and the associated transitions.
|
||||||
|
* The states and the transitions are methods
|
||||||
|
* The states are the actions.
|
||||||
|
* The transitions are tests : return false if the test do not match, or true
|
||||||
|
* if the test match. The state machine will skip the test if it doesn't match,
|
||||||
|
* and go to the define toStateName if the test return true.
|
||||||
|
* Officially, the transitions should not have priority. In practise, the
|
||||||
|
* transistions are tested in the added order.
|
||||||
|
*/
|
||||||
|
class StateMachine
|
||||||
|
{
|
||||||
|
private $states = array();
|
||||||
|
private $transitions = array();
|
||||||
|
private $debug = false;
|
||||||
|
|
||||||
|
public function addState(string $stateName, callable $methodName): self
|
||||||
|
{
|
||||||
|
$this->states[$stateName] = new StateMachineState($methodName);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addTransition(string $transitionName, string $fromStateName, string $toStateName, callable $methodName): self
|
||||||
|
{
|
||||||
|
if (! key_exists($fromStateName, $this->states))
|
||||||
|
throw new \Exception("StateMachine can not add Transition from '$fromStateName' : state not defined", 404);
|
||||||
|
if (! key_exists($toStateName, $this->states))
|
||||||
|
throw new \Exception("StateMachine can not add Transition to '$toStateName' : state not defined", 404);
|
||||||
|
if (key_exists($transitionName, $this->transitions))
|
||||||
|
throw new \Exception("StateMachine can not add Transition '$transitionName' : transition already defined", 406);
|
||||||
|
$this->transitions[$transitionName] = new StateMachineTransition($fromStateName, $toStateName, $methodName);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the state machine at the provided state
|
||||||
|
* Will run until no transition match, then return
|
||||||
|
*/
|
||||||
|
public function run(string $stateName)
|
||||||
|
{
|
||||||
|
if (! key_exists ($stateName, $this->states))
|
||||||
|
throw new \Exception("StateMachine can not runState '$stateName' : state not defined", 404);
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
$this->debug("Start state '$stateName'");
|
||||||
|
$rc = $this->states[$stateName]->run();
|
||||||
|
$this->debug("End state '$stateName' with type '".gettype($rc)."'");
|
||||||
|
foreach($this->transitions as $transitionName => $transition)
|
||||||
|
{
|
||||||
|
if ($transition->getFromStateName() !== $stateName)
|
||||||
|
continue;
|
||||||
|
if ($transition->run() === false)
|
||||||
|
{
|
||||||
|
$this->debug("Look at transition '$transitionName' : Return FALSE (not match)");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->debug("Look at transition '$transitionName' : Match");
|
||||||
|
$stateName = $transition->getToStateName();
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function debug(string $msg)
|
||||||
|
{
|
||||||
|
if ($this->debug === false)
|
||||||
|
return;
|
||||||
|
echo "$msg\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StateMachineState
|
||||||
|
{
|
||||||
|
private $methodName;
|
||||||
|
|
||||||
|
public function __construct(callable $methodName)
|
||||||
|
{
|
||||||
|
$this->methodName = $methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
return call_user_func($this->methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StateMachineTransition
|
||||||
|
{
|
||||||
|
private $fromStateName;
|
||||||
|
private $toStateName;
|
||||||
|
private $methodName;
|
||||||
|
|
||||||
|
public function __construct(string $fromStateName, string $toStateName, callable $methodName)
|
||||||
|
{
|
||||||
|
$this->fromStateName = $fromStateName;
|
||||||
|
$this->toStateName = $toStateName;
|
||||||
|
$this->methodName = $methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromStateName(): string
|
||||||
|
{
|
||||||
|
return $this->fromStateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getToStateName(): string
|
||||||
|
{
|
||||||
|
return $this->toStateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMethodName(): callable
|
||||||
|
{
|
||||||
|
return $this->methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
return call_user_func($this->methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user