Passed
Push — master ( e7d8df...846a27 )
by Théo
02:41
created

Terminal::readFromProcess()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
c 0
b 0
f 0
dl 0
loc 22
rs 9.8333
cc 3
nc 3
nop 1
1
<?php
2
3
/*
4
 * This file is part of the box project.
5
 *
6
 * (c) Kevin Herrera <[email protected]>
7
 *     Théo Fidry <[email protected]>
8
 *
9
 * This source file is subject to the MIT license that is bundled
10
 * with this source code in the file LICENSE.
11
 */
12
13
namespace KevinGH\RequirementChecker;
14
15
/**
16
 * This file is copy/pasted from the Symfony project to avoid a dependency on `symfony/console` which would be too big for just using this
17
 * class.
18
 *
19
 * @license MIT (c) Fabien Potencier <[email protected]>
20
 */
21
class Terminal
22
{
23
    private static $width;
24
    private static $height;
25
26
    /**
27
     * Gets the terminal width.
28
     *
29
     * @return int
30
     */
31
    public function getWidth()
32
    {
33
        $width = getenv('COLUMNS');
34
        if (false !== $width) {
35
            return (int) trim($width);
36
        }
37
38
        if (null === self::$width) {
39
            self::initDimensions();
40
        }
41
42
        return self::$width ?: 80;
43
    }
44
45
    /**
46
     * Gets the terminal height.
47
     *
48
     * @return int
49
     */
50
    public function getHeight()
51
    {
52
        $height = getenv('LINES');
53
        if (false !== $height) {
54
            return (int) trim($height);
55
        }
56
57
        if (null === self::$height) {
58
            self::initDimensions();
59
        }
60
61
        return self::$height ?: 50;
62
    }
63
64
    private static function initDimensions()
65
    {
66
        if ('\\' === \DIRECTORY_SEPARATOR) {
67
            if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) {
68
                // extract [w, H] from "wxh (WxH)"
69
                // or [w, h] from "wxh"
70
                self::$width = (int) $matches[1];
71
                self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
72
            } elseif (null !== $dimensions = self::getConsoleMode()) {
73
                // extract [w, h] from "wxh"
74
                self::$width = (int) $dimensions[0];
75
                self::$height = (int) $dimensions[1];
76
            }
77
        } elseif ($sttyString = self::getSttyColumns()) {
78
            if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
79
                // extract [w, h] from "rows h; columns w;"
80
                self::$width = (int) $matches[2];
81
                self::$height = (int) $matches[1];
82
            } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
83
                // extract [w, h] from "; h rows; w columns"
84
                self::$width = (int) $matches[2];
85
                self::$height = (int) $matches[1];
86
            }
87
        }
88
    }
89
90
    /**
91
     * Runs and parses mode CON if it's available, suppressing any error output.
92
     *
93
     * @return int[]|null An array composed of the width and the height or null if it could not be parsed
94
     */
95
    private static function getConsoleMode()
96
    {
97
        $info = self::readFromProcess('mode CON');
98
99
        if (null === $info || !preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) {
100
            return null;
101
        }
102
103
        return array((int) $matches[2], (int) $matches[1]);
104
    }
105
106
    /**
107
     * Runs and parses stty -a if it's available, suppressing any error output.
108
     *
109
     * @return string|null
110
     */
111
    private static function getSttyColumns()
112
    {
113
        return self::readFromProcess('stty -a | grep columns');
114
    }
115
116
    /**
117
     * @param string $command
118
     *
119
     * @return string|null
120
     */
121
    private static function readFromProcess($command)
122
    {
123
        if (!\function_exists('proc_open')) {
124
            return null;
125
        }
126
127
        $descriptorspec = array(
128
            1 => array('pipe', 'w'),
129
            2 => array('pipe', 'w'),
130
        );
131
132
        $process = proc_open($command, $descriptorspec, $pipes, null, null, array('suppress_errors' => true));
133
        if (!\is_resource($process)) {
134
            return null;
135
        }
136
137
        $info = stream_get_contents($pipes[1]);
138
        fclose($pipes[1]);
139
        fclose($pipes[2]);
140
        proc_close($process);
141
142
        return $info;
143
    }
144
}
145