Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / Console / Adapter / WindowsAnsicon.php
blob850c8f11fd72181d3d26d72238560fdfbddddb76
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\Console\Adapter;
12 use Zend\Console\Charset;
13 use Zend\Console\Charset\CharsetInterface;
14 use Zend\Console\Exception;
16 /**
17 * MS Windows with ANSICON console adapter
19 * This adapter requires ANSICON extension to be installed. It can be obtained from:
20 * https://github.com/adoxa/ansicon
22 * ANSICON has to be loaded and enabled before using this adapter. It's best to install
23 * it using following command:
24 * ansicon -I
26 * Console should not run in UTF8 code page (65001), because ANSICON does not behave well with it.
27 * It's best to use non-unicode code page 437, 850, 851, 852 or similar. Run "help mode" for more
28 * information on how to change Windows console code page.
30 class WindowsAnsicon extends Posix
32 /**
33 * Whether or not mbstring is enabled
35 * @var null|bool
37 protected static $hasMBString;
39 /**
40 * Results of mode command
42 * @var mixed
44 protected $modeResult;
46 /**
47 * Determine and return current console width.
49 * @return int
51 public function getWidth()
53 static $width;
54 if ($width > 0) {
55 return $width;
58 // Try to read console size from ANSICON env var
59 if (preg_match('/\((\d+)x/', getenv('ANSICON'), $matches)) {
60 $width = $matches[1];
61 } else {
62 $width = AbstractAdapter::getWidth();
65 return $width;
68 /**
69 * Determine and return current console height.
71 * @return false|int
73 public function getHeight()
75 static $height;
76 if ($height > 0) {
77 return $height;
80 // Try to read console size from ANSICON env var
81 if (preg_match('/\(\d+x(\d+)/', getenv('ANSICON'), $matches)) {
82 $height = $matches[1];
83 } else {
84 $height = AbstractAdapter::getHeight();
86 return $height;
89 /**
90 * Run and cache results of mode command
92 * @return void
94 protected function runModeCommand()
96 exec('mode', $output, $return);
97 if ($return || !count($output)) {
98 $this->modeResult = '';
99 } else {
100 $this->modeResult = trim(implode('', $output));
105 * Check if console is UTF-8 compatible
107 * @return bool
109 public function isUtf8()
111 // Try to read code page info from "mode" command
112 if ($this->modeResult === null) {
113 $this->runModeCommand();
116 if (preg_match('/Code page\:\s+(\d+)/', $this->modeResult, $matches)) {
117 return (int) $matches[1] == 65001;
120 return false;
124 * Return current console window title.
126 * @return string
128 public function getTitle()
130 // Try to use powershell to retrieve console window title
131 exec('powershell -command "write $Host.UI.RawUI.WindowTitle"', $output, $result);
132 if ($result || !$output) {
133 return '';
136 return trim($output, "\r\n");
140 * Clear console screen
142 public function clear()
144 echo chr(27) . '[1J' . chr(27) . '[u';
148 * Clear line at cursor position
150 public function clearLine()
152 echo chr(27) . '[1K';
156 * Set Console charset to use.
158 * @param CharsetInterface $charset
160 public function setCharset(CharsetInterface $charset)
162 $this->charset = $charset;
166 * Get charset currently in use by this adapter.
169 * @return CharsetInterface $charset
171 public function getCharset()
173 if ($this->charset === null) {
174 $this->charset = $this->getDefaultCharset();
177 return $this->charset;
181 * @return Charset\AsciiExtended
183 public function getDefaultCharset()
185 return new Charset\AsciiExtended();
189 * Read a single character from the console input
191 * @param string|null $mask A list of allowed chars
192 * @return string
193 * @throws Exception\RuntimeException
195 public function readChar($mask = null)
197 // Decide if we can use `choice` tool
198 $useChoice = $mask !== null && preg_match('/^[a-zA-Z0-9]+$/D', $mask);
200 if ($useChoice) {
201 // Use Windows 98+ "choice" command, which allows for reading a
202 // single character matching a mask, but is limited to lower ASCII
203 // range.
204 do {
205 exec('choice /n /cs /c:' . $mask, $output, $return);
206 if ($return == 255 || $return < 1 || $return > strlen($mask)) {
207 throw new Exception\RuntimeException('"choice" command failed to run. Are you using Windows XP or newer?');
210 // Fetch the char from mask
211 $char = substr($mask, $return - 1, 1);
212 } while ("" === $char || ($mask !== null && false === strstr($mask, $char)));
214 return $char;
217 // Try to use PowerShell, giving it console access. Because PowersShell
218 // interpreter can take a short while to load, we are emptying the
219 // whole keyboard buffer and picking the last key that has been pressed
220 // before or after PowerShell command has started. The ASCII code for
221 // that key is then converted to a character.
222 if ($mask === null) {
223 exec(
224 'powershell -NonInteractive -NoProfile -NoLogo -OutputFormat Text -Command "'
225 . 'while ($Host.UI.RawUI.KeyAvailable) {$key = $Host.UI.RawUI.ReadKey(\'NoEcho,IncludeKeyDown\');}'
226 . 'write $key.VirtualKeyCode;'
227 . '"',
228 $result,
229 $return
232 // Retrieve char from the result.
233 $char = !empty($result) ? implode('', $result) : null;
235 if (!empty($char) && !$return) {
236 // We have obtained an ASCII code, convert back to a char ...
237 $char = chr($char);
239 // ... and return it...
240 return $char;
242 } else {
243 // Windows and DOS will return carriage-return char (ASCII 13) when
244 // the user presses [ENTER] key, but Console Adapter user might
245 // have provided a \n Newline (ASCII 10) in the mask, to allow
246 // [ENTER]. We are going to replace all CR with NL to conform.
247 $mask = strtr($mask, "\n", "\r");
249 // Prepare a list of ASCII codes from mask chars
250 $asciiMask = array_map(function ($char) {
251 return ord($char);
252 }, str_split($mask));
253 $asciiMask = array_unique($asciiMask);
255 // Char mask filtering is now handled by the PowerShell itself,
256 // because it's a much faster method than invoking PS interpreter
257 // after each mismatch. The command should return ASCII code of a
258 // matching key.
259 $result = $return = null;
260 exec(
261 'powershell -NonInteractive -NoProfile -NoLogo -OutputFormat Text -Command "'
262 . '[int[]] $mask = '.join(',', $asciiMask).';'
263 . 'do {'
264 . '$key = $Host.UI.RawUI.ReadKey(\'NoEcho,IncludeKeyDown\').VirtualKeyCode;'
265 . '} while( !($mask -contains $key) );'
266 . 'write $key;'
267 . '"',
268 $result,
269 $return
272 $char = !empty($result) ? trim(implode('', $result)) : null;
274 if (!$return && $char && ($mask === null || in_array($char, $asciiMask))) {
275 // We have obtained an ASCII code, check if it is a carriage
276 // return and normalize it as needed
277 if ($char == 13) {
278 $char = 10;
281 // Convert to a character
282 $char = chr($char);
284 // ... and return it...
285 return $char;
289 // Fall back to standard input, which on Windows does not allow reading
290 // a single character. This is a limitation of Windows streams
291 // implementation (not PHP) and this behavior cannot be changed with a
292 // command like "stty", known to POSIX systems.
293 $stream = fopen('php://stdin', 'rb');
294 do {
295 $char = fgetc($stream);
296 $char = substr(trim($char), 0, 1);
297 } while (!$char || ($mask !== null && !stristr($mask, $char)));
298 fclose($stream);
300 return $char;