7
|
1 <?php
|
|
2
|
|
3 namespace Sabre\VObject;
|
|
4
|
|
5 use
|
|
6 InvalidArgumentException;
|
|
7
|
|
8 /**
|
|
9 * This is the CLI interface for sabre-vobject.
|
|
10 *
|
|
11 * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).
|
|
12 * @author Evert Pot (http://evertpot.com/)
|
|
13 * @license http://sabre.io/license/ Modified BSD License
|
|
14 */
|
|
15 class Cli {
|
|
16
|
|
17 /**
|
|
18 * No output
|
|
19 *
|
|
20 * @var bool
|
|
21 */
|
|
22 protected $quiet = false;
|
|
23
|
|
24 /**
|
|
25 * Help display
|
|
26 *
|
|
27 * @var bool
|
|
28 */
|
|
29 protected $showHelp = false;
|
|
30
|
|
31 /**
|
|
32 * Wether to spit out 'mimedir' or 'json' format.
|
|
33 *
|
|
34 * @var string
|
|
35 */
|
|
36 protected $format;
|
|
37
|
|
38 /**
|
|
39 * JSON pretty print
|
|
40 *
|
|
41 * @var bool
|
|
42 */
|
|
43 protected $pretty;
|
|
44
|
|
45 /**
|
|
46 * Source file
|
|
47 *
|
|
48 * @var string
|
|
49 */
|
|
50 protected $inputPath;
|
|
51
|
|
52 /**
|
|
53 * Destination file
|
|
54 *
|
|
55 * @var string
|
|
56 */
|
|
57 protected $outputPath;
|
|
58
|
|
59 /**
|
|
60 * output stream
|
|
61 *
|
|
62 * @var resource
|
|
63 */
|
|
64 protected $stdout;
|
|
65
|
|
66 /**
|
|
67 * stdin
|
|
68 *
|
|
69 * @var resource
|
|
70 */
|
|
71 protected $stdin;
|
|
72
|
|
73 /**
|
|
74 * stderr
|
|
75 *
|
|
76 * @var resource
|
|
77 */
|
|
78 protected $stderr;
|
|
79
|
|
80 /**
|
|
81 * Input format (one of json or mimedir)
|
|
82 *
|
|
83 * @var string
|
|
84 */
|
|
85 protected $inputFormat;
|
|
86
|
|
87 /**
|
|
88 * Makes the parser less strict.
|
|
89 *
|
|
90 * @var bool
|
|
91 */
|
|
92 protected $forgiving = false;
|
|
93
|
|
94 /**
|
|
95 * Main function
|
|
96 *
|
|
97 * @return int
|
|
98 */
|
|
99 public function main(array $argv) {
|
|
100
|
|
101 // @codeCoverageIgnoreStart
|
|
102 // We cannot easily test this, so we'll skip it. Pretty basic anyway.
|
|
103
|
|
104 if (!$this->stderr) {
|
|
105 $this->stderr = fopen('php://stderr', 'w');
|
|
106 }
|
|
107 if (!$this->stdout) {
|
|
108 $this->stdout = fopen('php://stdout', 'w');
|
|
109 }
|
|
110 if (!$this->stdin) {
|
|
111 $this->stdin = fopen('php://stdin', 'r');
|
|
112 }
|
|
113
|
|
114 // @codeCoverageIgnoreEnd
|
|
115
|
|
116
|
|
117 try {
|
|
118
|
|
119 list($options, $positional) = $this->parseArguments($argv);
|
|
120
|
|
121 if (isset($options['q'])) {
|
|
122 $this->quiet = true;
|
|
123 }
|
|
124 $this->log($this->colorize('green', "sabre/vobject ") . $this->colorize('yellow', Version::VERSION));
|
|
125
|
|
126 foreach($options as $name=>$value) {
|
|
127
|
|
128 switch($name) {
|
|
129
|
|
130 case 'q' :
|
|
131 // Already handled earlier.
|
|
132 break;
|
|
133 case 'h' :
|
|
134 case 'help' :
|
|
135 $this->showHelp();
|
|
136 return 0;
|
|
137 break;
|
|
138 case 'format' :
|
|
139 switch($value) {
|
|
140
|
|
141 // jcard/jcal documents
|
|
142 case 'jcard' :
|
|
143 case 'jcal' :
|
|
144
|
|
145 // specific document versions
|
|
146 case 'vcard21' :
|
|
147 case 'vcard30' :
|
|
148 case 'vcard40' :
|
|
149 case 'icalendar20' :
|
|
150
|
|
151 // specific formats
|
|
152 case 'json' :
|
|
153 case 'mimedir' :
|
|
154
|
|
155 // icalendar/vcad
|
|
156 case 'icalendar' :
|
|
157 case 'vcard' :
|
|
158 $this->format = $value;
|
|
159 break;
|
|
160
|
|
161 default :
|
|
162 throw new InvalidArgumentException('Unknown format: ' . $value);
|
|
163
|
|
164 }
|
|
165 break;
|
|
166 case 'pretty' :
|
|
167 if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
|
168 $this->pretty = true;
|
|
169 }
|
|
170 break;
|
|
171 case 'forgiving' :
|
|
172 $this->forgiving = true;
|
|
173 break;
|
|
174 case 'inputformat' :
|
|
175 switch($value) {
|
|
176 // json formats
|
|
177 case 'jcard' :
|
|
178 case 'jcal' :
|
|
179 case 'json' :
|
|
180 $this->inputFormat = 'json';
|
|
181 break;
|
|
182
|
|
183 // mimedir formats
|
|
184 case 'mimedir' :
|
|
185 case 'icalendar' :
|
|
186 case 'vcard' :
|
|
187 case 'vcard21' :
|
|
188 case 'vcard30' :
|
|
189 case 'vcard40' :
|
|
190 case 'icalendar20' :
|
|
191
|
|
192 $this->inputFormat = 'mimedir';
|
|
193 break;
|
|
194
|
|
195 default :
|
|
196 throw new InvalidArgumentException('Unknown format: ' . $value);
|
|
197
|
|
198 }
|
|
199 break;
|
|
200 default :
|
|
201 throw new InvalidArgumentException('Unknown option: ' . $name);
|
|
202
|
|
203 }
|
|
204
|
|
205 }
|
|
206
|
|
207 if (count($positional) === 0) {
|
|
208 $this->showHelp();
|
|
209 return 1;
|
|
210 }
|
|
211
|
|
212 if (count($positional) === 1) {
|
|
213 throw new InvalidArgumentException('Inputfile is a required argument');
|
|
214 }
|
|
215
|
|
216 if (count($positional) > 3) {
|
|
217 throw new InvalidArgumentException('Too many arguments');
|
|
218 }
|
|
219
|
|
220 if (!in_array($positional[0], array('validate','repair','convert','color'))) {
|
|
221 throw new InvalidArgumentException('Uknown command: ' . $positional[0]);
|
|
222 }
|
|
223
|
|
224 } catch (InvalidArgumentException $e) {
|
|
225 $this->showHelp();
|
|
226 $this->log('Error: ' . $e->getMessage(), 'red');
|
|
227 return 1;
|
|
228 }
|
|
229
|
|
230 $command = $positional[0];
|
|
231
|
|
232 $this->inputPath = $positional[1];
|
|
233 $this->outputPath = isset($positional[2])?$positional[2]:'-';
|
|
234
|
|
235 if ($this->outputPath !== '-') {
|
|
236 $this->stdout = fopen($this->outputPath, 'w');
|
|
237 }
|
|
238
|
|
239 if (!$this->inputFormat) {
|
|
240 if (substr($this->inputPath, -5)==='.json') {
|
|
241 $this->inputFormat = 'json';
|
|
242 } else {
|
|
243 $this->inputFormat = 'mimedir';
|
|
244 }
|
|
245 }
|
|
246 if (!$this->format) {
|
|
247 if (substr($this->outputPath,-5)==='.json') {
|
|
248 $this->format = 'json';
|
|
249 } else {
|
|
250 $this->format = 'mimedir';
|
|
251 }
|
|
252 }
|
|
253
|
|
254
|
|
255 $realCode = 0;
|
|
256
|
|
257 try {
|
|
258
|
|
259 while($input = $this->readInput()) {
|
|
260
|
|
261 $returnCode = $this->$command($input);
|
|
262 if ($returnCode!==0) $realCode = $returnCode;
|
|
263
|
|
264 }
|
|
265
|
|
266 } catch (EofException $e) {
|
|
267 // end of file
|
|
268 } catch (\Exception $e) {
|
|
269 $this->log('Error: ' . $e->getMessage(),'red');
|
|
270 return 2;
|
|
271 }
|
|
272
|
|
273 return $realCode;
|
|
274
|
|
275 }
|
|
276
|
|
277 /**
|
|
278 * Shows the help message.
|
|
279 *
|
|
280 * @return void
|
|
281 */
|
|
282 protected function showHelp() {
|
|
283
|
|
284 $this->log('Usage:', 'yellow');
|
|
285 $this->log(" vobject [options] command [arguments]");
|
|
286 $this->log('');
|
|
287 $this->log('Options:', 'yellow');
|
|
288 $this->log($this->colorize('green', ' -q ') . "Don't output anything.");
|
|
289 $this->log($this->colorize('green', ' -help -h ') . "Display this help message.");
|
|
290 $this->log($this->colorize('green', ' --format ') . "Convert to a specific format. Must be one of: vcard, vcard21,");
|
|
291 $this->log($this->colorize('green', ' --forgiving ') . "Makes the parser less strict.");
|
|
292 $this->log(" vcard30, vcard40, icalendar20, jcal, jcard, json, mimedir.");
|
|
293 $this->log($this->colorize('green', ' --inputformat ') . "If the input format cannot be guessed from the extension, it");
|
|
294 $this->log(" must be specified here.");
|
|
295 // Only PHP 5.4 and up
|
|
296 if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
|
297 $this->log($this->colorize('green', ' --pretty ') . "json pretty-print.");
|
|
298 }
|
|
299 $this->log('');
|
|
300 $this->log('Commands:', 'yellow');
|
|
301 $this->log($this->colorize('green', ' validate') . ' source_file Validates a file for correctness.');
|
|
302 $this->log($this->colorize('green', ' repair') . ' source_file [output_file] Repairs a file.');
|
|
303 $this->log($this->colorize('green', ' convert') . ' source_file [output_file] Converts a file.');
|
|
304 $this->log($this->colorize('green', ' color') . ' source_file Colorize a file, useful for debbugging.');
|
|
305 $this->log(
|
|
306 <<<HELP
|
|
307
|
|
308 If source_file is set as '-', STDIN will be used.
|
|
309 If output_file is omitted, STDOUT will be used.
|
|
310 All other output is sent to STDERR.
|
|
311
|
|
312 HELP
|
|
313 );
|
|
314
|
|
315 $this->log('Examples:', 'yellow');
|
|
316 $this->log(' vobject convert contact.vcf contact.json');
|
|
317 $this->log(' vobject convert --format=vcard40 old.vcf new.vcf');
|
|
318 $this->log(' vobject convert --inputformat=json --format=mimedir - -');
|
|
319 $this->log(' vobject color calendar.ics');
|
|
320 $this->log('');
|
|
321 $this->log('https://github.com/fruux/sabre-vobject','purple');
|
|
322
|
|
323 }
|
|
324
|
|
325 /**
|
|
326 * Validates a VObject file
|
|
327 *
|
|
328 * @param Component $vObj
|
|
329 * @return int
|
|
330 */
|
|
331 protected function validate($vObj) {
|
|
332
|
|
333 $returnCode = 0;
|
|
334
|
|
335 switch($vObj->name) {
|
|
336 case 'VCALENDAR' :
|
|
337 $this->log("iCalendar: " . (string)$vObj->VERSION);
|
|
338 break;
|
|
339 case 'VCARD' :
|
|
340 $this->log("vCard: " . (string)$vObj->VERSION);
|
|
341 break;
|
|
342 }
|
|
343
|
|
344 $warnings = $vObj->validate();
|
|
345 if (!count($warnings)) {
|
|
346 $this->log(" No warnings!");
|
|
347 } else {
|
|
348
|
|
349 $levels = array(
|
|
350 1 => 'REPAIRED',
|
|
351 2 => 'WARNING',
|
|
352 3 => 'ERROR',
|
|
353 );
|
|
354 $returnCode = 2;
|
|
355 foreach($warnings as $warn) {
|
|
356
|
|
357 $extra = '';
|
|
358 if ($warn['node'] instanceof Property) {
|
|
359 $extra = ' (property: "' . $warn['node']->name . '")';
|
|
360 }
|
|
361 $this->log(" [" . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
|
|
362
|
|
363 }
|
|
364
|
|
365 }
|
|
366
|
|
367 return $returnCode;
|
|
368
|
|
369 }
|
|
370
|
|
371 /**
|
|
372 * Repairs a VObject file
|
|
373 *
|
|
374 * @param Component $vObj
|
|
375 * @return int
|
|
376 */
|
|
377 protected function repair($vObj) {
|
|
378
|
|
379 $returnCode = 0;
|
|
380
|
|
381 switch($vObj->name) {
|
|
382 case 'VCALENDAR' :
|
|
383 $this->log("iCalendar: " . (string)$vObj->VERSION);
|
|
384 break;
|
|
385 case 'VCARD' :
|
|
386 $this->log("vCard: " . (string)$vObj->VERSION);
|
|
387 break;
|
|
388 }
|
|
389
|
|
390 $warnings = $vObj->validate(Node::REPAIR);
|
|
391 if (!count($warnings)) {
|
|
392 $this->log(" No warnings!");
|
|
393 } else {
|
|
394
|
|
395 $levels = array(
|
|
396 1 => 'REPAIRED',
|
|
397 2 => 'WARNING',
|
|
398 3 => 'ERROR',
|
|
399 );
|
|
400 $returnCode = 2;
|
|
401 foreach($warnings as $warn) {
|
|
402
|
|
403 $extra = '';
|
|
404 if ($warn['node'] instanceof Property) {
|
|
405 $extra = ' (property: "' . $warn['node']->name . '")';
|
|
406 }
|
|
407 $this->log(" [" . $levels[$warn['level']] . '] ' . $warn['message'] . $extra);
|
|
408
|
|
409 }
|
|
410
|
|
411 }
|
|
412 fwrite($this->stdout, $vObj->serialize());
|
|
413
|
|
414 return $returnCode;
|
|
415
|
|
416 }
|
|
417
|
|
418 /**
|
|
419 * Converts a vObject file to a new format.
|
|
420 *
|
|
421 * @param Component $vObj
|
|
422 * @return int
|
|
423 */
|
|
424 protected function convert($vObj) {
|
|
425
|
|
426 $json = false;
|
|
427 $convertVersion = null;
|
|
428 $forceInput = null;
|
|
429
|
|
430 switch($this->format) {
|
|
431 case 'json' :
|
|
432 $json = true;
|
|
433 if ($vObj->name === 'VCARD') {
|
|
434 $convertVersion = Document::VCARD40;
|
|
435 }
|
|
436 break;
|
|
437 case 'jcard' :
|
|
438 $json = true;
|
|
439 $forceInput = 'VCARD';
|
|
440 $convertVersion = Document::VCARD40;
|
|
441 break;
|
|
442 case 'jcal' :
|
|
443 $json = true;
|
|
444 $forceInput = 'VCALENDAR';
|
|
445 break;
|
|
446 case 'mimedir' :
|
|
447 case 'icalendar' :
|
|
448 case 'icalendar20' :
|
|
449 case 'vcard' :
|
|
450 break;
|
|
451 case 'vcard21' :
|
|
452 $convertVersion = Document::VCARD21;
|
|
453 break;
|
|
454 case 'vcard30' :
|
|
455 $convertVersion = Document::VCARD30;
|
|
456 break;
|
|
457 case 'vcard40' :
|
|
458 $convertVersion = Document::VCARD40;
|
|
459 break;
|
|
460
|
|
461 }
|
|
462
|
|
463 if ($forceInput && $vObj->name !== $forceInput) {
|
|
464 throw new \Exception('You cannot convert a ' . strtolower($vObj->name) . ' to ' . $this->format);
|
|
465 }
|
|
466 if ($convertVersion) {
|
|
467 $vObj = $vObj->convert($convertVersion);
|
|
468 }
|
|
469 if ($json) {
|
|
470 $jsonOptions = 0;
|
|
471 if ($this->pretty) {
|
|
472 $jsonOptions = JSON_PRETTY_PRINT;
|
|
473 }
|
|
474 fwrite($this->stdout, json_encode($vObj->jsonSerialize(), $jsonOptions));
|
|
475 } else {
|
|
476 fwrite($this->stdout, $vObj->serialize());
|
|
477 }
|
|
478
|
|
479 return 0;
|
|
480
|
|
481 }
|
|
482
|
|
483 /**
|
|
484 * Colorizes a file
|
|
485 *
|
|
486 * @param Component $vObj
|
|
487 * @return int
|
|
488 */
|
|
489 protected function color($vObj) {
|
|
490
|
|
491 fwrite($this->stdout, $this->serializeComponent($vObj));
|
|
492
|
|
493 }
|
|
494
|
|
495 /**
|
|
496 * Returns an ansi color string for a color name.
|
|
497 *
|
|
498 * @param string $color
|
|
499 * @return string
|
|
500 */
|
|
501 protected function colorize($color, $str, $resetTo = 'default') {
|
|
502
|
|
503 $colors = array(
|
|
504 'cyan' => '1;36',
|
|
505 'red' => '1;31',
|
|
506 'yellow' => '1;33',
|
|
507 'blue' => '0;34',
|
|
508 'green' => '0;32',
|
|
509 'default' => '0',
|
|
510 'purple' => '0;35',
|
|
511 );
|
|
512 return "\033[" . $colors[$color] . 'm' . $str . "\033[".$colors[$resetTo]."m";
|
|
513
|
|
514 }
|
|
515
|
|
516 /**
|
|
517 * Writes out a string in specific color.
|
|
518 *
|
|
519 * @param string $color
|
|
520 * @param string $str
|
|
521 * @return void
|
|
522 */
|
|
523 protected function cWrite($color, $str) {
|
|
524
|
|
525 fwrite($this->stdout, $this->colorize($color, $str));
|
|
526
|
|
527 }
|
|
528
|
|
529 protected function serializeComponent(Component $vObj) {
|
|
530
|
|
531 $this->cWrite('cyan', 'BEGIN');
|
|
532 $this->cWrite('red', ':');
|
|
533 $this->cWrite('yellow', $vObj->name . "\n");
|
|
534
|
|
535 /**
|
|
536 * Gives a component a 'score' for sorting purposes.
|
|
537 *
|
|
538 * This is solely used by the childrenSort method.
|
|
539 *
|
|
540 * A higher score means the item will be lower in the list.
|
|
541 * To avoid score collisions, each "score category" has a reasonable
|
|
542 * space to accomodate elements. The $key is added to the $score to
|
|
543 * preserve the original relative order of elements.
|
|
544 *
|
|
545 * @param int $key
|
|
546 * @param array $array
|
|
547 * @return int
|
|
548 */
|
|
549 $sortScore = function($key, $array) {
|
|
550
|
|
551 if ($array[$key] instanceof Component) {
|
|
552
|
|
553 // We want to encode VTIMEZONE first, this is a personal
|
|
554 // preference.
|
|
555 if ($array[$key]->name === 'VTIMEZONE') {
|
|
556 $score=300000000;
|
|
557 return $score+$key;
|
|
558 } else {
|
|
559 $score=400000000;
|
|
560 return $score+$key;
|
|
561 }
|
|
562 } else {
|
|
563 // Properties get encoded first
|
|
564 // VCARD version 4.0 wants the VERSION property to appear first
|
|
565 if ($array[$key] instanceof Property) {
|
|
566 if ($array[$key]->name === 'VERSION') {
|
|
567 $score=100000000;
|
|
568 return $score+$key;
|
|
569 } else {
|
|
570 // All other properties
|
|
571 $score=200000000;
|
|
572 return $score+$key;
|
|
573 }
|
|
574 }
|
|
575 }
|
|
576
|
|
577 };
|
|
578
|
|
579 $tmp = $vObj->children;
|
|
580 uksort(
|
|
581 $vObj->children,
|
|
582 function($a, $b) use ($sortScore, $tmp) {
|
|
583
|
|
584 $sA = $sortScore($a, $tmp);
|
|
585 $sB = $sortScore($b, $tmp);
|
|
586
|
|
587 return $sA - $sB;
|
|
588
|
|
589 }
|
|
590 );
|
|
591
|
|
592 foreach($vObj->children as $child) {
|
|
593 if ($child instanceof Component) {
|
|
594 $this->serializeComponent($child);
|
|
595 } else {
|
|
596 $this->serializeProperty($child);
|
|
597 }
|
|
598 }
|
|
599
|
|
600 $this->cWrite('cyan', 'END');
|
|
601 $this->cWrite('red', ':');
|
|
602 $this->cWrite('yellow', $vObj->name . "\n");
|
|
603
|
|
604 }
|
|
605
|
|
606 /**
|
|
607 * Colorizes a property.
|
|
608 *
|
|
609 * @param Property $property
|
|
610 * @return void
|
|
611 */
|
|
612 protected function serializeProperty(Property $property) {
|
|
613
|
|
614 if ($property->group) {
|
|
615 $this->cWrite('default', $property->group);
|
|
616 $this->cWrite('red', '.');
|
|
617 }
|
|
618
|
|
619 $str = '';
|
|
620 $this->cWrite('yellow', $property->name);
|
|
621
|
|
622 foreach($property->parameters as $param) {
|
|
623
|
|
624 $this->cWrite('red',';');
|
|
625 $this->cWrite('blue', $param->serialize());
|
|
626
|
|
627 }
|
|
628 $this->cWrite('red',':');
|
|
629
|
|
630 if ($property instanceof Property\Binary) {
|
|
631
|
|
632 $this->cWrite('default', 'embedded binary stripped. (' . strlen($property->getValue()) . ' bytes)');
|
|
633
|
|
634 } else {
|
|
635
|
|
636 $parts = $property->getParts();
|
|
637 $first1 = true;
|
|
638 // Looping through property values
|
|
639 foreach($parts as $part) {
|
|
640 if ($first1) {
|
|
641 $first1 = false;
|
|
642 } else {
|
|
643 $this->cWrite('red', $property->delimiter);
|
|
644 }
|
|
645 $first2 = true;
|
|
646 // Looping through property sub-values
|
|
647 foreach((array)$part as $subPart) {
|
|
648 if ($first2) {
|
|
649 $first2 = false;
|
|
650 } else {
|
|
651 // The sub-value delimiter is always comma
|
|
652 $this->cWrite('red', ',');
|
|
653 }
|
|
654
|
|
655 $subPart = strtr(
|
|
656 $subPart,
|
|
657 array(
|
|
658 '\\' => $this->colorize('purple', '\\\\', 'green'),
|
|
659 ';' => $this->colorize('purple', '\;', 'green'),
|
|
660 ',' => $this->colorize('purple', '\,', 'green'),
|
|
661 "\n" => $this->colorize('purple', "\\n\n\t", 'green'),
|
|
662 "\r" => "",
|
|
663 )
|
|
664 );
|
|
665
|
|
666 $this->cWrite('green', $subPart);
|
|
667 }
|
|
668 }
|
|
669
|
|
670 }
|
|
671 $this->cWrite("default", "\n");
|
|
672
|
|
673 }
|
|
674
|
|
675 /**
|
|
676 * Parses the list of arguments.
|
|
677 *
|
|
678 * @param array $argv
|
|
679 * @return void
|
|
680 */
|
|
681 protected function parseArguments(array $argv) {
|
|
682
|
|
683 $positional = array();
|
|
684 $options = array();
|
|
685
|
|
686 for($ii=0; $ii < count($argv); $ii++) {
|
|
687
|
|
688 // Skipping the first argument.
|
|
689 if ($ii===0) continue;
|
|
690
|
|
691 $v = $argv[$ii];
|
|
692
|
|
693 if (substr($v,0,2)==='--') {
|
|
694 // This is a long-form option.
|
|
695 $optionName = substr($v,2);
|
|
696 $optionValue = true;
|
|
697 if (strpos($optionName,'=')) {
|
|
698 list($optionName, $optionValue) = explode('=', $optionName);
|
|
699 }
|
|
700 $options[$optionName] = $optionValue;
|
|
701 } elseif (substr($v,0,1) === '-' && strlen($v)>1) {
|
|
702 // This is a short-form option.
|
|
703 foreach(str_split(substr($v,1)) as $option) {
|
|
704 $options[$option] = true;
|
|
705 }
|
|
706
|
|
707 } else {
|
|
708
|
|
709 $positional[] = $v;
|
|
710
|
|
711 }
|
|
712
|
|
713 }
|
|
714
|
|
715 return array($options, $positional);
|
|
716
|
|
717 }
|
|
718
|
|
719 protected $parser;
|
|
720
|
|
721 /**
|
|
722 * Reads the input file
|
|
723 *
|
|
724 * @return Component
|
|
725 */
|
|
726 protected function readInput() {
|
|
727
|
|
728 if (!$this->parser) {
|
|
729 if ($this->inputPath!=='-') {
|
|
730 $this->stdin = fopen($this->inputPath,'r');
|
|
731 }
|
|
732
|
|
733 if ($this->inputFormat === 'mimedir') {
|
|
734 $this->parser = new Parser\MimeDir($this->stdin, ($this->forgiving?Reader::OPTION_FORGIVING:0));
|
|
735 } else {
|
|
736 $this->parser = new Parser\Json($this->stdin, ($this->forgiving?Reader::OPTION_FORGIVING:0));
|
|
737 }
|
|
738 }
|
|
739
|
|
740 return $this->parser->parse();
|
|
741
|
|
742 }
|
|
743
|
|
744 /**
|
|
745 * Sends a message to STDERR.
|
|
746 *
|
|
747 * @param string $msg
|
|
748 * @return void
|
|
749 */
|
|
750 protected function log($msg, $color = 'default') {
|
|
751
|
|
752 if (!$this->quiet) {
|
|
753 if ($color!=='default') {
|
|
754 $msg = $this->colorize($color, $msg);
|
|
755 }
|
|
756 fwrite($this->stderr, $msg . "\n");
|
|
757 }
|
|
758
|
|
759 }
|
|
760
|
|
761 }
|