xref: /plugin/pagecss/vendor/csstidy-2.2.1/bin/pcsstidy (revision 7d6669007238fef7e8728f167d637ed824899eb0)
1*7d666900SdWiGhT#!/usr/bin/env php
2*7d666900SdWiGhT<?php
3*7d666900SdWiGhT/**
4*7d666900SdWiGhT * CSSTidy - Command Line Interface (CLI)
5*7d666900SdWiGhT *
6*7d666900SdWiGhT * This file is part of CSSTidy.
7*7d666900SdWiGhT *
8*7d666900SdWiGhT *   CSSTidy is free software; you can redistribute it and/or modify
9*7d666900SdWiGhT *   it under the terms of the GNU Lesser General Public License as published by
10*7d666900SdWiGhT *   the Free Software Foundation; either version 2.1 of the License, or
11*7d666900SdWiGhT *   (at your option) any later version.
12*7d666900SdWiGhT *
13*7d666900SdWiGhT *   CSSTidy is distributed in the hope that it will be useful,
14*7d666900SdWiGhT *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15*7d666900SdWiGhT *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*7d666900SdWiGhT *   GNU Lesser General Public License for more details.
17*7d666900SdWiGhT *
18*7d666900SdWiGhT *   You should have received a copy of the GNU Lesser General Public License
19*7d666900SdWiGhT *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*7d666900SdWiGhT *
21*7d666900SdWiGhT * @license http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
22*7d666900SdWiGhT * @package csstidy
23*7d666900SdWiGhT * @author Florian Schmitz (floele at gmail dot com) 2005-2007
24*7d666900SdWiGhT * @author Brett Zamir (brettz9 at yahoo dot com) 2007
25*7d666900SdWiGhT * @author Nikolay Matsievsky (speed at webo dot name) 2009-2010
26*7d666900SdWiGhT * @author Christopher Finke (cfinke at gmail.com) 2012
27*7d666900SdWiGhT * @author Etienne Desautels (etienne dot desautels at gmail dot com) 2012
28*7d666900SdWiGhT * @author Cedric Morin (cedric at yterium dot com) 2010-2019
29*7d666900SdWiGhT */
30*7d666900SdWiGhT
31*7d666900SdWiGhT
32*7d666900SdWiGhTerror_reporting(E_ALL);
33*7d666900SdWiGhT
34*7d666900SdWiGhTif (version_compare(PHP_VERSION, '5.4')<0){
35*7d666900SdWiGhT	die('Requires PHP 5.4 or above');
36*7d666900SdWiGhT}
37*7d666900SdWiGhT
38*7d666900SdWiGhT/**
39*7d666900SdWiGhT * Contains the Parser class
40*7d666900SdWiGhT *
41*7d666900SdWiGhT * @version 1.6.5
42*7d666900SdWiGhT */
43*7d666900SdWiGhTrequire dirname(__DIR__) . DIRECTORY_SEPARATOR . 'class.csstidy.php';
44*7d666900SdWiGhT$csstidy = new csstidy();
45*7d666900SdWiGhT$dumpTree = false;
46*7d666900SdWiGhT$default_media = '';
47*7d666900SdWiGhT
48*7d666900SdWiGhT/**
49*7d666900SdWiGhT * Return the usage message to sdterr and exit with return code 1
50*7d666900SdWiGhT * @access private
51*7d666900SdWiGhT * @version 1.0
52*7d666900SdWiGhT */
53*7d666900SdWiGhTfunction _show_usage(){
54*7d666900SdWiGhT	$exe = $GLOBALS['argv'][0];
55*7d666900SdWiGhT	$version = "Version " . $GLOBALS['csstidy']->version;
56*7d666900SdWiGhT
57*7d666900SdWiGhT	$HELP = <<<EOT
58*7d666900SdWiGhTUsage: $exe [options] [input-file]
59*7d666900SdWiGhT$version
60*7d666900SdWiGhT
61*7d666900SdWiGhTOptions include:
62*7d666900SdWiGhT
63*7d666900SdWiGhT-h, --help                   Show this message
64*7d666900SdWiGhT-t=template                  Set the output template [default|filename|low|high|highest]
65*7d666900SdWiGhT--case_properties            [1|2|0]
66*7d666900SdWiGhT--compress_colors            [true|false]
67*7d666900SdWiGhT--compress_font-weight       [true|false]
68*7d666900SdWiGhT--default_media              Set the default media rule to apply to the CSS
69*7d666900SdWiGhT--css_level                  [CSS3.0|CSS2.1|CSS2.0|CSS1.0]
70*7d666900SdWiGhT--discard_invalid_properties [false|true]
71*7d666900SdWiGhT--discard_invalid_selectors  [false|true]
72*7d666900SdWiGhT--lowercase_s                [false|true]
73*7d666900SdWiGhT--merge_selectors            [0|1|2]
74*7d666900SdWiGhT--optimise_shorthands        [1|2|0]
75*7d666900SdWiGhT--preserve_css               [false|true]
76*7d666900SdWiGhT--remove_bslash              [true|false]
77*7d666900SdWiGhT--remove_last_semicolon      [false|true]
78*7d666900SdWiGhT--reverse_left_and_right     [false|true]
79*7d666900SdWiGhT--sort_properties            [false|true]
80*7d666900SdWiGhT--sort_selectors             [false|true]
81*7d666900SdWiGhT--timestamp                  [false|true]
82*7d666900SdWiGhT
83*7d666900SdWiGhT-T                  Dump formatted parse tree
84*7d666900SdWiGhT-v, --version       Print the version
85*7d666900SdWiGhT
86*7d666900SdWiGhTEOT;
87*7d666900SdWiGhT	exit($HELP);
88*7d666900SdWiGhT}
89*7d666900SdWiGhT
90*7d666900SdWiGhT
91*7d666900SdWiGhT/**
92*7d666900SdWiGhT * Parse argument
93*7d666900SdWiGhT *
94*7d666900SdWiGhT * @param integer $i
95*7d666900SdWiGhT * @param array $options
96*7d666900SdWiGhT *
97*7d666900SdWiGhT * @return string|null
98*7d666900SdWiGhT */
99*7d666900SdWiGhTfunction parseArgument(&$i, $options){
100*7d666900SdWiGhT	global $argc;
101*7d666900SdWiGhT	global $argv;
102*7d666900SdWiGhT
103*7d666900SdWiGhT	if (!preg_match('/^(?:' . implode('|', (array)$options) . ')=?(.*)/', $argv[$i], $matches)){
104*7d666900SdWiGhT		return;
105*7d666900SdWiGhT	}
106*7d666900SdWiGhT
107*7d666900SdWiGhT	if (strlen($matches[1])){
108*7d666900SdWiGhT		return $matches[1];
109*7d666900SdWiGhT	}
110*7d666900SdWiGhT
111*7d666900SdWiGhT	if ($i+1<$argc){
112*7d666900SdWiGhT		$i++;
113*7d666900SdWiGhT
114*7d666900SdWiGhT		return $argv[$i];
115*7d666900SdWiGhT	}
116*7d666900SdWiGhT}
117*7d666900SdWiGhT
118*7d666900SdWiGhT/**
119*7d666900SdWiGhT * Cast Arguments relative to expected format
120*7d666900SdWiGhT * @param mixed $value
121*7d666900SdWiGhT * @param string $format
122*7d666900SdWiGhT * @param array $expected
123*7d666900SdWiGhT * @return mixed
124*7d666900SdWiGhT */
125*7d666900SdWiGhTfunction castArgument($value, $format, $expected = null) {
126*7d666900SdWiGhT	if ($expected and !in_array($value, $expected)) {
127*7d666900SdWiGhT		if (in_array('filename', $expected)) {
128*7d666900SdWiGhT			$fileName = castArgument($value, $format);
129*7d666900SdWiGhT			if (!file_exists($fileName)) {
130*7d666900SdWiGhT				_show_usage();
131*7d666900SdWiGhT			}
132*7d666900SdWiGhT		}
133*7d666900SdWiGhT		else {
134*7d666900SdWiGhT			_show_usage();
135*7d666900SdWiGhT		}
136*7d666900SdWiGhT	}
137*7d666900SdWiGhT	switch (strtolower($format)) {
138*7d666900SdWiGhT		case "int":
139*7d666900SdWiGhT			$value = intval($value);
140*7d666900SdWiGhT			break;
141*7d666900SdWiGhT		case "str":
142*7d666900SdWiGhT			$value = trim(strval($value));
143*7d666900SdWiGhT			foreach (["'", '"'] as $q) {
144*7d666900SdWiGhT				if (substr($value, 0, 1) == $q && substr($value, -1, 1) == $q) {
145*7d666900SdWiGhT					$value = substr($value, 1, -1);
146*7d666900SdWiGhT					$value = str_replace("\\" . $q, $q, $value);
147*7d666900SdWiGhT					break;
148*7d666900SdWiGhT				}
149*7d666900SdWiGhT			}
150*7d666900SdWiGhT			break;
151*7d666900SdWiGhT		case "bool":
152*7d666900SdWiGhT			$value = strtolower(trim(strval($value)));
153*7d666900SdWiGhT			if (!in_array($value, [ '0', '1', 'on', 'off', 'true', 'false'])) {
154*7d666900SdWiGhT				_show_usage();
155*7d666900SdWiGhT			}
156*7d666900SdWiGhT			$value = (in_array(strtolower($value), ['1', 'on', 'true']) ? true : false);
157*7d666900SdWiGhT			break;
158*7d666900SdWiGhT	}
159*7d666900SdWiGhT	return $value;
160*7d666900SdWiGhT}
161*7d666900SdWiGhT
162*7d666900SdWiGhT// Check if there's at least one argument
163*7d666900SdWiGhTif ($argc<1){
164*7d666900SdWiGhT	_show_usage();
165*7d666900SdWiGhT}
166*7d666900SdWiGhT
167*7d666900SdWiGhT// Set the settings defined on the CLI
168*7d666900SdWiGhT$settings = [
169*7d666900SdWiGhT	'case_properties' => ['format' => 'int', 'expected' => [0, 1, 2]],
170*7d666900SdWiGhT	'compress_colors' => ['format' => 'bool'],
171*7d666900SdWiGhT	'compress_font-weight' => ['format' => 'bool'],
172*7d666900SdWiGhT	'css_level' => ['format' => 'str', 'expected' => ['CSS3.0', 'CSS2.1', 'CSS2.0', 'CSS1.0']],
173*7d666900SdWiGhT	'discard_invalid_properties' => ['format' => 'bool'],
174*7d666900SdWiGhT	'discard_invalid_selectors' => ['format' => 'bool'],
175*7d666900SdWiGhT	'merge_selectors' => ['format' => 'int', 'expected' => [0, 1, 2]],
176*7d666900SdWiGhT	'lowercase_s' => ['format' => 'bool'],
177*7d666900SdWiGhT	'optimise_shorthands' => ['format' => 'int', 'expected' => [0, 1, 2]],
178*7d666900SdWiGhT	'preserve_css' => ['format' => 'bool'],
179*7d666900SdWiGhT	'remove_bslash' => ['format' => 'bool'],
180*7d666900SdWiGhT	'remove_last_semicolon' => ['format' => 'bool', 'setting' => 'remove_last_;'],
181*7d666900SdWiGhT	'reverse_left_and_right' => ['format' => 'bool'],
182*7d666900SdWiGhT	'sort_properties' => ['format' => 'bool'],
183*7d666900SdWiGhT	'sort_selectors' => ['format' => 'bool'],
184*7d666900SdWiGhT	'template' => ['format' => 'str', 'short' => 't', 'expected' => ['default', 'filename', 'low', 'high', 'highest']],
185*7d666900SdWiGhT	'timestamp' => ['format' => 'bool'],
186*7d666900SdWiGhT];
187*7d666900SdWiGhT
188*7d666900SdWiGhTforeach ($settings as $option_name => $desc) {
189*7d666900SdWiGhT	$options_list = [ "--$option_name" ];
190*7d666900SdWiGhT	if (isset($desc['short'])) {
191*7d666900SdWiGhT		$options_list[] = "-" . $desc['short'];
192*7d666900SdWiGhT	}
193*7d666900SdWiGhT	$settings[$option_name]['options_list'] = $options_list;
194*7d666900SdWiGhT}
195*7d666900SdWiGhT
196*7d666900SdWiGhT
197*7d666900SdWiGhTfor ($i = 1; $i<$argc; $i++){
198*7d666900SdWiGhT	if ($argv[$i]==='-h' || $argv[$i]==='--help'){
199*7d666900SdWiGhT		_show_usage();
200*7d666900SdWiGhT	}
201*7d666900SdWiGhT
202*7d666900SdWiGhT	if ($argv[$i]==='-v' || $argv[$i]==='--version'){
203*7d666900SdWiGhT		exit($csstidy->version . "\n");
204*7d666900SdWiGhT	}
205*7d666900SdWiGhT	$value = parseArgument($i, ['--default_media']);
206*7d666900SdWiGhT	if (isset($value)) {
207*7d666900SdWiGhT		$value = castArgument($value, 'str');
208*7d666900SdWiGhT		$default_media = trim($value);
209*7d666900SdWiGhT		if (strpos($default_media, '@') === false) {
210*7d666900SdWiGhT			$default_media = '@media ' . $default_media;
211*7d666900SdWiGhT		}
212*7d666900SdWiGhT	}
213*7d666900SdWiGhT
214*7d666900SdWiGhT	foreach ($settings as $option_name => $desc) {
215*7d666900SdWiGhT		$value = parseArgument($i, $desc['options_list']);
216*7d666900SdWiGhT		if (isset($value)){
217*7d666900SdWiGhT			if (isset($desc['format'])) {
218*7d666900SdWiGhT				$value = castArgument($value, $desc['format'], isset($desc['expected']) ? $desc['expected'] : null);
219*7d666900SdWiGhT			}
220*7d666900SdWiGhT			$setting_name = $option_name;
221*7d666900SdWiGhT			if (isset($desc['setting'])) {
222*7d666900SdWiGhT				$setting_name = $desc['setting'];
223*7d666900SdWiGhT			}
224*7d666900SdWiGhT			$csstidy->set_cfg($setting_name, $value);
225*7d666900SdWiGhT			continue 2;
226*7d666900SdWiGhT		}
227*7d666900SdWiGhT	}
228*7d666900SdWiGhT
229*7d666900SdWiGhT	if ($argv[$i]==='-T'){
230*7d666900SdWiGhT		$dumpTree = true;
231*7d666900SdWiGhT		continue;
232*7d666900SdWiGhT	}
233*7d666900SdWiGhT
234*7d666900SdWiGhT	if (file_exists($argv[$i])){
235*7d666900SdWiGhT		$inputFile = $argv[$i];
236*7d666900SdWiGhT		continue;
237*7d666900SdWiGhT	}
238*7d666900SdWiGhT}
239*7d666900SdWiGhT
240*7d666900SdWiGhTif (!$inputFile) {
241*7d666900SdWiGhT	$inputFile = 'php://stdin';
242*7d666900SdWiGhT}
243*7d666900SdWiGhT
244*7d666900SdWiGhT// Get the data
245*7d666900SdWiGhT$css_code = file_get_contents($inputFile);
246*7d666900SdWiGhT
247*7d666900SdWiGhT// Exit on error when reading the data
248*7d666900SdWiGhTif ($css_code===false){
249*7d666900SdWiGhT	file_put_contents('php://stderr', "The file \"" . $inputFile . "\" does not exist.\n");
250*7d666900SdWiGhT	exit(1);
251*7d666900SdWiGhT}
252*7d666900SdWiGhT
253*7d666900SdWiGhT// Parse the CSS
254*7d666900SdWiGhT$csstidy->parse($css_code);
255*7d666900SdWiGhTif ($dumpTree){
256*7d666900SdWiGhT	var_dump($csstidy->css);
257*7d666900SdWiGhT} else {
258*7d666900SdWiGhT	// Optimize and output the CSS file
259*7d666900SdWiGhT	echo $csstidy->print->plain($default_media);
260*7d666900SdWiGhT	echo "\n";
261*7d666900SdWiGhT}