1 | <?php |
---|
2 | /** |
---|
3 | * PEAR_Frontend_CLI |
---|
4 | * |
---|
5 | * PHP versions 4 and 5 |
---|
6 | * |
---|
7 | * @category pear |
---|
8 | * @package PEAR |
---|
9 | * @author Stig Bakken <ssb@php.net> |
---|
10 | * @author Greg Beaver <cellog@php.net> |
---|
11 | * @copyright 1997-2009 The Authors |
---|
12 | * @license http://opensource.org/licenses/bsd-license.php New BSD License |
---|
13 | * @version CVS: $Id: CLI.php 313023 2011-07-06 19:17:11Z dufuz $ |
---|
14 | * @link http://pear.php.net/package/PEAR |
---|
15 | * @since File available since Release 0.1 |
---|
16 | */ |
---|
17 | /** |
---|
18 | * base class |
---|
19 | */ |
---|
20 | require_once 'PEAR/Frontend.php'; |
---|
21 | |
---|
22 | /** |
---|
23 | * Command-line Frontend for the PEAR Installer |
---|
24 | * @category pear |
---|
25 | * @package PEAR |
---|
26 | * @author Stig Bakken <ssb@php.net> |
---|
27 | * @author Greg Beaver <cellog@php.net> |
---|
28 | * @copyright 1997-2009 The Authors |
---|
29 | * @license http://opensource.org/licenses/bsd-license.php New BSD License |
---|
30 | * @version Release: 1.9.4 |
---|
31 | * @link http://pear.php.net/package/PEAR |
---|
32 | * @since Class available since Release 0.1 |
---|
33 | */ |
---|
34 | class PEAR_Frontend_CLI extends PEAR_Frontend |
---|
35 | { |
---|
36 | /** |
---|
37 | * What type of user interface this frontend is for. |
---|
38 | * @var string |
---|
39 | * @access public |
---|
40 | */ |
---|
41 | var $type = 'CLI'; |
---|
42 | var $lp = ''; // line prefix |
---|
43 | |
---|
44 | var $params = array(); |
---|
45 | var $term = array( |
---|
46 | 'bold' => '', |
---|
47 | 'normal' => '', |
---|
48 | ); |
---|
49 | |
---|
50 | function PEAR_Frontend_CLI() |
---|
51 | { |
---|
52 | parent::PEAR(); |
---|
53 | $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1 |
---|
54 | if (function_exists('posix_isatty') && !posix_isatty(1)) { |
---|
55 | // output is being redirected to a file or through a pipe |
---|
56 | } elseif ($term) { |
---|
57 | if (preg_match('/^(xterm|vt220|linux)/', $term)) { |
---|
58 | $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109); |
---|
59 | $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109); |
---|
60 | } elseif (preg_match('/^vt100/', $term)) { |
---|
61 | $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); |
---|
62 | $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0); |
---|
63 | } |
---|
64 | } elseif (OS_WINDOWS) { |
---|
65 | // XXX add ANSI codes here |
---|
66 | } |
---|
67 | } |
---|
68 | |
---|
69 | /** |
---|
70 | * @param object PEAR_Error object |
---|
71 | */ |
---|
72 | function displayError($e) |
---|
73 | { |
---|
74 | return $this->_displayLine($e->getMessage()); |
---|
75 | } |
---|
76 | |
---|
77 | /** |
---|
78 | * @param object PEAR_Error object |
---|
79 | */ |
---|
80 | function displayFatalError($eobj) |
---|
81 | { |
---|
82 | $this->displayError($eobj); |
---|
83 | if (class_exists('PEAR_Config')) { |
---|
84 | $config = &PEAR_Config::singleton(); |
---|
85 | if ($config->get('verbose') > 5) { |
---|
86 | if (function_exists('debug_print_backtrace')) { |
---|
87 | debug_print_backtrace(); |
---|
88 | exit(1); |
---|
89 | } |
---|
90 | |
---|
91 | $raised = false; |
---|
92 | foreach (debug_backtrace() as $i => $frame) { |
---|
93 | if (!$raised) { |
---|
94 | if (isset($frame['class']) |
---|
95 | && strtolower($frame['class']) == 'pear' |
---|
96 | && strtolower($frame['function']) == 'raiseerror' |
---|
97 | ) { |
---|
98 | $raised = true; |
---|
99 | } else { |
---|
100 | continue; |
---|
101 | } |
---|
102 | } |
---|
103 | |
---|
104 | $frame['class'] = !isset($frame['class']) ? '' : $frame['class']; |
---|
105 | $frame['type'] = !isset($frame['type']) ? '' : $frame['type']; |
---|
106 | $frame['function'] = !isset($frame['function']) ? '' : $frame['function']; |
---|
107 | $frame['line'] = !isset($frame['line']) ? '' : $frame['line']; |
---|
108 | $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]"); |
---|
109 | } |
---|
110 | } |
---|
111 | } |
---|
112 | |
---|
113 | exit(1); |
---|
114 | } |
---|
115 | |
---|
116 | /** |
---|
117 | * Instruct the runInstallScript method to skip a paramgroup that matches the |
---|
118 | * id value passed in. |
---|
119 | * |
---|
120 | * This method is useful for dynamically configuring which sections of a post-install script |
---|
121 | * will be run based on the user's setup, which is very useful for making flexible |
---|
122 | * post-install scripts without losing the cross-Frontend ability to retrieve user input |
---|
123 | * @param string |
---|
124 | */ |
---|
125 | function skipParamgroup($id) |
---|
126 | { |
---|
127 | $this->_skipSections[$id] = true; |
---|
128 | } |
---|
129 | |
---|
130 | function runPostinstallScripts(&$scripts) |
---|
131 | { |
---|
132 | foreach ($scripts as $i => $script) { |
---|
133 | $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj); |
---|
134 | } |
---|
135 | } |
---|
136 | |
---|
137 | /** |
---|
138 | * @param array $xml contents of postinstallscript tag |
---|
139 | * @param object $script post-installation script |
---|
140 | * @param string install|upgrade |
---|
141 | */ |
---|
142 | function runInstallScript($xml, &$script) |
---|
143 | { |
---|
144 | $this->_skipSections = array(); |
---|
145 | if (!is_array($xml) || !isset($xml['paramgroup'])) { |
---|
146 | $script->run(array(), '_default'); |
---|
147 | return; |
---|
148 | } |
---|
149 | |
---|
150 | $completedPhases = array(); |
---|
151 | if (!isset($xml['paramgroup'][0])) { |
---|
152 | $xml['paramgroup'] = array($xml['paramgroup']); |
---|
153 | } |
---|
154 | |
---|
155 | foreach ($xml['paramgroup'] as $group) { |
---|
156 | if (isset($this->_skipSections[$group['id']])) { |
---|
157 | // the post-install script chose to skip this section dynamically |
---|
158 | continue; |
---|
159 | } |
---|
160 | |
---|
161 | if (isset($group['name'])) { |
---|
162 | $paramname = explode('::', $group['name']); |
---|
163 | if ($lastgroup['id'] != $paramname[0]) { |
---|
164 | continue; |
---|
165 | } |
---|
166 | |
---|
167 | $group['name'] = $paramname[1]; |
---|
168 | if (!isset($answers)) { |
---|
169 | return; |
---|
170 | } |
---|
171 | |
---|
172 | if (isset($answers[$group['name']])) { |
---|
173 | switch ($group['conditiontype']) { |
---|
174 | case '=' : |
---|
175 | if ($answers[$group['name']] != $group['value']) { |
---|
176 | continue 2; |
---|
177 | } |
---|
178 | break; |
---|
179 | case '!=' : |
---|
180 | if ($answers[$group['name']] == $group['value']) { |
---|
181 | continue 2; |
---|
182 | } |
---|
183 | break; |
---|
184 | case 'preg_match' : |
---|
185 | if (!@preg_match('/' . $group['value'] . '/', |
---|
186 | $answers[$group['name']])) { |
---|
187 | continue 2; |
---|
188 | } |
---|
189 | break; |
---|
190 | default : |
---|
191 | return; |
---|
192 | } |
---|
193 | } |
---|
194 | } |
---|
195 | |
---|
196 | $lastgroup = $group; |
---|
197 | if (isset($group['instructions'])) { |
---|
198 | $this->_display($group['instructions']); |
---|
199 | } |
---|
200 | |
---|
201 | if (!isset($group['param'][0])) { |
---|
202 | $group['param'] = array($group['param']); |
---|
203 | } |
---|
204 | |
---|
205 | if (isset($group['param'])) { |
---|
206 | if (method_exists($script, 'postProcessPrompts')) { |
---|
207 | $prompts = $script->postProcessPrompts($group['param'], $group['id']); |
---|
208 | if (!is_array($prompts) || count($prompts) != count($group['param'])) { |
---|
209 | $this->outputData('postinstall', 'Error: post-install script did not ' . |
---|
210 | 'return proper post-processed prompts'); |
---|
211 | $prompts = $group['param']; |
---|
212 | } else { |
---|
213 | foreach ($prompts as $i => $var) { |
---|
214 | if (!is_array($var) || !isset($var['prompt']) || |
---|
215 | !isset($var['name']) || |
---|
216 | ($var['name'] != $group['param'][$i]['name']) || |
---|
217 | ($var['type'] != $group['param'][$i]['type']) |
---|
218 | ) { |
---|
219 | $this->outputData('postinstall', 'Error: post-install script ' . |
---|
220 | 'modified the variables or prompts, severe security risk. ' . |
---|
221 | 'Will instead use the defaults from the package.xml'); |
---|
222 | $prompts = $group['param']; |
---|
223 | } |
---|
224 | } |
---|
225 | } |
---|
226 | |
---|
227 | $answers = $this->confirmDialog($prompts); |
---|
228 | } else { |
---|
229 | $answers = $this->confirmDialog($group['param']); |
---|
230 | } |
---|
231 | } |
---|
232 | |
---|
233 | if ((isset($answers) && $answers) || !isset($group['param'])) { |
---|
234 | if (!isset($answers)) { |
---|
235 | $answers = array(); |
---|
236 | } |
---|
237 | |
---|
238 | array_unshift($completedPhases, $group['id']); |
---|
239 | if (!$script->run($answers, $group['id'])) { |
---|
240 | $script->run($completedPhases, '_undoOnError'); |
---|
241 | return; |
---|
242 | } |
---|
243 | } else { |
---|
244 | $script->run($completedPhases, '_undoOnError'); |
---|
245 | return; |
---|
246 | } |
---|
247 | } |
---|
248 | } |
---|
249 | |
---|
250 | /** |
---|
251 | * Ask for user input, confirm the answers and continue until the user is satisfied |
---|
252 | * @param array an array of arrays, format array('name' => 'paramname', 'prompt' => |
---|
253 | * 'text to display', 'type' => 'string'[, default => 'default value']) |
---|
254 | * @return array |
---|
255 | */ |
---|
256 | function confirmDialog($params) |
---|
257 | { |
---|
258 | $answers = $prompts = $types = array(); |
---|
259 | foreach ($params as $param) { |
---|
260 | $prompts[$param['name']] = $param['prompt']; |
---|
261 | $types[$param['name']] = $param['type']; |
---|
262 | $answers[$param['name']] = isset($param['default']) ? $param['default'] : ''; |
---|
263 | } |
---|
264 | |
---|
265 | $tried = false; |
---|
266 | do { |
---|
267 | if ($tried) { |
---|
268 | $i = 1; |
---|
269 | foreach ($answers as $var => $value) { |
---|
270 | if (!strlen($value)) { |
---|
271 | echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n"); |
---|
272 | } |
---|
273 | $i++; |
---|
274 | } |
---|
275 | } |
---|
276 | |
---|
277 | $answers = $this->userDialog('', $prompts, $types, $answers); |
---|
278 | $tried = true; |
---|
279 | } while (is_array($answers) && count(array_filter($answers)) != count($prompts)); |
---|
280 | |
---|
281 | return $answers; |
---|
282 | } |
---|
283 | |
---|
284 | function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20) |
---|
285 | { |
---|
286 | if (!is_array($prompts)) { |
---|
287 | return array(); |
---|
288 | } |
---|
289 | |
---|
290 | $testprompts = array_keys($prompts); |
---|
291 | $result = $defaults; |
---|
292 | |
---|
293 | reset($prompts); |
---|
294 | if (count($prompts) === 1) { |
---|
295 | foreach ($prompts as $key => $prompt) { |
---|
296 | $type = $types[$key]; |
---|
297 | $default = @$defaults[$key]; |
---|
298 | print "$prompt "; |
---|
299 | if ($default) { |
---|
300 | print "[$default] "; |
---|
301 | } |
---|
302 | print ": "; |
---|
303 | |
---|
304 | $line = fgets(STDIN, 2048); |
---|
305 | $result[$key] = ($default && trim($line) == '') ? $default : trim($line); |
---|
306 | } |
---|
307 | |
---|
308 | return $result; |
---|
309 | } |
---|
310 | |
---|
311 | $first_run = true; |
---|
312 | while (true) { |
---|
313 | $descLength = max(array_map('strlen', $prompts)); |
---|
314 | $descFormat = "%-{$descLength}s"; |
---|
315 | $last = count($prompts); |
---|
316 | |
---|
317 | $i = 0; |
---|
318 | foreach ($prompts as $n => $var) { |
---|
319 | $res = isset($result[$n]) ? $result[$n] : null; |
---|
320 | printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res); |
---|
321 | } |
---|
322 | print "\n1-$last, 'all', 'abort', or Enter to continue: "; |
---|
323 | |
---|
324 | $tmp = trim(fgets(STDIN, 1024)); |
---|
325 | if (empty($tmp)) { |
---|
326 | break; |
---|
327 | } |
---|
328 | |
---|
329 | if ($tmp == 'abort') { |
---|
330 | return false; |
---|
331 | } |
---|
332 | |
---|
333 | if (isset($testprompts[(int)$tmp - 1])) { |
---|
334 | $var = $testprompts[(int)$tmp - 1]; |
---|
335 | $desc = $prompts[$var]; |
---|
336 | $current = @$result[$var]; |
---|
337 | print "$desc [$current] : "; |
---|
338 | $tmp = trim(fgets(STDIN, 1024)); |
---|
339 | if ($tmp !== '') { |
---|
340 | $result[$var] = $tmp; |
---|
341 | } |
---|
342 | } elseif ($tmp == 'all') { |
---|
343 | foreach ($prompts as $var => $desc) { |
---|
344 | $current = $result[$var]; |
---|
345 | print "$desc [$current] : "; |
---|
346 | $tmp = trim(fgets(STDIN, 1024)); |
---|
347 | if (trim($tmp) !== '') { |
---|
348 | $result[$var] = trim($tmp); |
---|
349 | } |
---|
350 | } |
---|
351 | } |
---|
352 | |
---|
353 | $first_run = false; |
---|
354 | } |
---|
355 | |
---|
356 | return $result; |
---|
357 | } |
---|
358 | |
---|
359 | function userConfirm($prompt, $default = 'yes') |
---|
360 | { |
---|
361 | trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR); |
---|
362 | static $positives = array('y', 'yes', 'on', '1'); |
---|
363 | static $negatives = array('n', 'no', 'off', '0'); |
---|
364 | print "$this->lp$prompt [$default] : "; |
---|
365 | $fp = fopen("php://stdin", "r"); |
---|
366 | $line = fgets($fp, 2048); |
---|
367 | fclose($fp); |
---|
368 | $answer = strtolower(trim($line)); |
---|
369 | if (empty($answer)) { |
---|
370 | $answer = $default; |
---|
371 | } |
---|
372 | if (in_array($answer, $positives)) { |
---|
373 | return true; |
---|
374 | } |
---|
375 | if (in_array($answer, $negatives)) { |
---|
376 | return false; |
---|
377 | } |
---|
378 | if (in_array($default, $positives)) { |
---|
379 | return true; |
---|
380 | } |
---|
381 | return false; |
---|
382 | } |
---|
383 | |
---|
384 | function outputData($data, $command = '_default') |
---|
385 | { |
---|
386 | switch ($command) { |
---|
387 | case 'channel-info': |
---|
388 | foreach ($data as $type => $section) { |
---|
389 | if ($type == 'main') { |
---|
390 | $section['data'] = array_values($section['data']); |
---|
391 | } |
---|
392 | |
---|
393 | $this->outputData($section); |
---|
394 | } |
---|
395 | break; |
---|
396 | case 'install': |
---|
397 | case 'upgrade': |
---|
398 | case 'upgrade-all': |
---|
399 | if (is_array($data) && isset($data['release_warnings'])) { |
---|
400 | $this->_displayLine(''); |
---|
401 | $this->_startTable(array( |
---|
402 | 'border' => false, |
---|
403 | 'caption' => 'Release Warnings' |
---|
404 | )); |
---|
405 | $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55))); |
---|
406 | $this->_endTable(); |
---|
407 | $this->_displayLine(''); |
---|
408 | } |
---|
409 | |
---|
410 | $this->_displayLine(is_array($data) ? $data['data'] : $data); |
---|
411 | break; |
---|
412 | case 'search': |
---|
413 | $this->_startTable($data); |
---|
414 | if (isset($data['headline']) && is_array($data['headline'])) { |
---|
415 | $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); |
---|
416 | } |
---|
417 | |
---|
418 | $packages = array(); |
---|
419 | foreach($data['data'] as $category) { |
---|
420 | foreach($category as $name => $pkg) { |
---|
421 | $packages[$pkg[0]] = $pkg; |
---|
422 | } |
---|
423 | } |
---|
424 | |
---|
425 | $p = array_keys($packages); |
---|
426 | natcasesort($p); |
---|
427 | foreach ($p as $name) { |
---|
428 | $this->_tableRow($packages[$name], null, array(1 => array('wrap' => 55))); |
---|
429 | } |
---|
430 | |
---|
431 | $this->_endTable(); |
---|
432 | break; |
---|
433 | case 'list-all': |
---|
434 | if (!isset($data['data'])) { |
---|
435 | $this->_displayLine('No packages in channel'); |
---|
436 | break; |
---|
437 | } |
---|
438 | |
---|
439 | $this->_startTable($data); |
---|
440 | if (isset($data['headline']) && is_array($data['headline'])) { |
---|
441 | $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); |
---|
442 | } |
---|
443 | |
---|
444 | $packages = array(); |
---|
445 | foreach($data['data'] as $category) { |
---|
446 | foreach($category as $name => $pkg) { |
---|
447 | $packages[$pkg[0]] = $pkg; |
---|
448 | } |
---|
449 | } |
---|
450 | |
---|
451 | $p = array_keys($packages); |
---|
452 | natcasesort($p); |
---|
453 | foreach ($p as $name) { |
---|
454 | $pkg = $packages[$name]; |
---|
455 | unset($pkg[4], $pkg[5]); |
---|
456 | $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); |
---|
457 | } |
---|
458 | |
---|
459 | $this->_endTable(); |
---|
460 | break; |
---|
461 | case 'config-show': |
---|
462 | $data['border'] = false; |
---|
463 | $opts = array( |
---|
464 | 0 => array('wrap' => 30), |
---|
465 | 1 => array('wrap' => 20), |
---|
466 | 2 => array('wrap' => 35) |
---|
467 | ); |
---|
468 | |
---|
469 | $this->_startTable($data); |
---|
470 | if (isset($data['headline']) && is_array($data['headline'])) { |
---|
471 | $this->_tableRow($data['headline'], array('bold' => true), $opts); |
---|
472 | } |
---|
473 | |
---|
474 | foreach ($data['data'] as $group) { |
---|
475 | foreach ($group as $value) { |
---|
476 | if ($value[2] == '') { |
---|
477 | $value[2] = "<not set>"; |
---|
478 | } |
---|
479 | |
---|
480 | $this->_tableRow($value, null, $opts); |
---|
481 | } |
---|
482 | } |
---|
483 | |
---|
484 | $this->_endTable(); |
---|
485 | break; |
---|
486 | case 'remote-info': |
---|
487 | $d = $data; |
---|
488 | $data = array( |
---|
489 | 'caption' => 'Package details:', |
---|
490 | 'border' => false, |
---|
491 | 'data' => array( |
---|
492 | array("Latest", $data['stable']), |
---|
493 | array("Installed", $data['installed']), |
---|
494 | array("Package", $data['name']), |
---|
495 | array("License", $data['license']), |
---|
496 | array("Category", $data['category']), |
---|
497 | array("Summary", $data['summary']), |
---|
498 | array("Description", $data['description']), |
---|
499 | ), |
---|
500 | ); |
---|
501 | |
---|
502 | if (isset($d['deprecated']) && $d['deprecated']) { |
---|
503 | $conf = &PEAR_Config::singleton(); |
---|
504 | $reg = $conf->getRegistry(); |
---|
505 | $name = $reg->parsedPackageNameToString($d['deprecated'], true); |
---|
506 | $data['data'][] = array('Deprecated! use', $name); |
---|
507 | } |
---|
508 | default: { |
---|
509 | if (is_array($data)) { |
---|
510 | $this->_startTable($data); |
---|
511 | $count = count($data['data'][0]); |
---|
512 | if ($count == 2) { |
---|
513 | $opts = array(0 => array('wrap' => 25), |
---|
514 | 1 => array('wrap' => 48) |
---|
515 | ); |
---|
516 | } elseif ($count == 3) { |
---|
517 | $opts = array(0 => array('wrap' => 30), |
---|
518 | 1 => array('wrap' => 20), |
---|
519 | 2 => array('wrap' => 35) |
---|
520 | ); |
---|
521 | } else { |
---|
522 | $opts = null; |
---|
523 | } |
---|
524 | if (isset($data['headline']) && is_array($data['headline'])) { |
---|
525 | $this->_tableRow($data['headline'], |
---|
526 | array('bold' => true), |
---|
527 | $opts); |
---|
528 | } |
---|
529 | |
---|
530 | if (is_array($data['data'])) { |
---|
531 | foreach($data['data'] as $row) { |
---|
532 | $this->_tableRow($row, null, $opts); |
---|
533 | } |
---|
534 | } else { |
---|
535 | $this->_tableRow(array($data['data']), null, $opts); |
---|
536 | } |
---|
537 | $this->_endTable(); |
---|
538 | } else { |
---|
539 | $this->_displayLine($data); |
---|
540 | } |
---|
541 | } |
---|
542 | } |
---|
543 | } |
---|
544 | |
---|
545 | function log($text, $append_crlf = true) |
---|
546 | { |
---|
547 | if ($append_crlf) { |
---|
548 | return $this->_displayLine($text); |
---|
549 | } |
---|
550 | |
---|
551 | return $this->_display($text); |
---|
552 | } |
---|
553 | |
---|
554 | function bold($text) |
---|
555 | { |
---|
556 | if (empty($this->term['bold'])) { |
---|
557 | return strtoupper($text); |
---|
558 | } |
---|
559 | |
---|
560 | return $this->term['bold'] . $text . $this->term['normal']; |
---|
561 | } |
---|
562 | |
---|
563 | function _displayHeading($title) |
---|
564 | { |
---|
565 | print $this->lp.$this->bold($title)."\n"; |
---|
566 | print $this->lp.str_repeat("=", strlen($title))."\n"; |
---|
567 | } |
---|
568 | |
---|
569 | function _startTable($params = array()) |
---|
570 | { |
---|
571 | $params['table_data'] = array(); |
---|
572 | $params['widest'] = array(); // indexed by column |
---|
573 | $params['highest'] = array(); // indexed by row |
---|
574 | $params['ncols'] = 0; |
---|
575 | $this->params = $params; |
---|
576 | } |
---|
577 | |
---|
578 | function _tableRow($columns, $rowparams = array(), $colparams = array()) |
---|
579 | { |
---|
580 | $highest = 1; |
---|
581 | for ($i = 0; $i < count($columns); $i++) { |
---|
582 | $col = &$columns[$i]; |
---|
583 | if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) { |
---|
584 | $col = wordwrap($col, $colparams[$i]['wrap']); |
---|
585 | } |
---|
586 | |
---|
587 | if (strpos($col, "\n") !== false) { |
---|
588 | $multiline = explode("\n", $col); |
---|
589 | $w = 0; |
---|
590 | foreach ($multiline as $n => $line) { |
---|
591 | $len = strlen($line); |
---|
592 | if ($len > $w) { |
---|
593 | $w = $len; |
---|
594 | } |
---|
595 | } |
---|
596 | $lines = count($multiline); |
---|
597 | } else { |
---|
598 | $w = strlen($col); |
---|
599 | } |
---|
600 | |
---|
601 | if (isset($this->params['widest'][$i])) { |
---|
602 | if ($w > $this->params['widest'][$i]) { |
---|
603 | $this->params['widest'][$i] = $w; |
---|
604 | } |
---|
605 | } else { |
---|
606 | $this->params['widest'][$i] = $w; |
---|
607 | } |
---|
608 | |
---|
609 | $tmp = count_chars($columns[$i], 1); |
---|
610 | // handle unix, mac and windows formats |
---|
611 | $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1; |
---|
612 | if ($lines > $highest) { |
---|
613 | $highest = $lines; |
---|
614 | } |
---|
615 | } |
---|
616 | |
---|
617 | if (count($columns) > $this->params['ncols']) { |
---|
618 | $this->params['ncols'] = count($columns); |
---|
619 | } |
---|
620 | |
---|
621 | $new_row = array( |
---|
622 | 'data' => $columns, |
---|
623 | 'height' => $highest, |
---|
624 | 'rowparams' => $rowparams, |
---|
625 | 'colparams' => $colparams, |
---|
626 | ); |
---|
627 | $this->params['table_data'][] = $new_row; |
---|
628 | } |
---|
629 | |
---|
630 | function _endTable() |
---|
631 | { |
---|
632 | extract($this->params); |
---|
633 | if (!empty($caption)) { |
---|
634 | $this->_displayHeading($caption); |
---|
635 | } |
---|
636 | |
---|
637 | if (count($table_data) === 0) { |
---|
638 | return; |
---|
639 | } |
---|
640 | |
---|
641 | if (!isset($width)) { |
---|
642 | $width = $widest; |
---|
643 | } else { |
---|
644 | for ($i = 0; $i < $ncols; $i++) { |
---|
645 | if (!isset($width[$i])) { |
---|
646 | $width[$i] = $widest[$i]; |
---|
647 | } |
---|
648 | } |
---|
649 | } |
---|
650 | |
---|
651 | $border = false; |
---|
652 | if (empty($border)) { |
---|
653 | $cellstart = ''; |
---|
654 | $cellend = ' '; |
---|
655 | $rowend = ''; |
---|
656 | $padrowend = false; |
---|
657 | $borderline = ''; |
---|
658 | } else { |
---|
659 | $cellstart = '| '; |
---|
660 | $cellend = ' '; |
---|
661 | $rowend = '|'; |
---|
662 | $padrowend = true; |
---|
663 | $borderline = '+'; |
---|
664 | foreach ($width as $w) { |
---|
665 | $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1); |
---|
666 | $borderline .= '+'; |
---|
667 | } |
---|
668 | } |
---|
669 | |
---|
670 | if ($borderline) { |
---|
671 | $this->_displayLine($borderline); |
---|
672 | } |
---|
673 | |
---|
674 | for ($i = 0; $i < count($table_data); $i++) { |
---|
675 | extract($table_data[$i]); |
---|
676 | if (!is_array($rowparams)) { |
---|
677 | $rowparams = array(); |
---|
678 | } |
---|
679 | |
---|
680 | if (!is_array($colparams)) { |
---|
681 | $colparams = array(); |
---|
682 | } |
---|
683 | |
---|
684 | $rowlines = array(); |
---|
685 | if ($height > 1) { |
---|
686 | for ($c = 0; $c < count($data); $c++) { |
---|
687 | $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]); |
---|
688 | if (count($rowlines[$c]) < $height) { |
---|
689 | $rowlines[$c] = array_pad($rowlines[$c], $height, ''); |
---|
690 | } |
---|
691 | } |
---|
692 | } else { |
---|
693 | for ($c = 0; $c < count($data); $c++) { |
---|
694 | $rowlines[$c] = array($data[$c]); |
---|
695 | } |
---|
696 | } |
---|
697 | |
---|
698 | for ($r = 0; $r < $height; $r++) { |
---|
699 | $rowtext = ''; |
---|
700 | for ($c = 0; $c < count($data); $c++) { |
---|
701 | if (isset($colparams[$c])) { |
---|
702 | $attribs = array_merge($rowparams, $colparams); |
---|
703 | } else { |
---|
704 | $attribs = $rowparams; |
---|
705 | } |
---|
706 | |
---|
707 | $w = isset($width[$c]) ? $width[$c] : 0; |
---|
708 | //$cell = $data[$c]; |
---|
709 | $cell = $rowlines[$c][$r]; |
---|
710 | $l = strlen($cell); |
---|
711 | if ($l > $w) { |
---|
712 | $cell = substr($cell, 0, $w); |
---|
713 | } |
---|
714 | |
---|
715 | if (isset($attribs['bold'])) { |
---|
716 | $cell = $this->bold($cell); |
---|
717 | } |
---|
718 | |
---|
719 | if ($l < $w) { |
---|
720 | // not using str_pad here because we may |
---|
721 | // add bold escape characters to $cell |
---|
722 | $cell .= str_repeat(' ', $w - $l); |
---|
723 | } |
---|
724 | |
---|
725 | $rowtext .= $cellstart . $cell . $cellend; |
---|
726 | } |
---|
727 | |
---|
728 | if (!$border) { |
---|
729 | $rowtext = rtrim($rowtext); |
---|
730 | } |
---|
731 | |
---|
732 | $rowtext .= $rowend; |
---|
733 | $this->_displayLine($rowtext); |
---|
734 | } |
---|
735 | } |
---|
736 | |
---|
737 | if ($borderline) { |
---|
738 | $this->_displayLine($borderline); |
---|
739 | } |
---|
740 | } |
---|
741 | |
---|
742 | function _displayLine($text) |
---|
743 | { |
---|
744 | print "$this->lp$text\n"; |
---|
745 | } |
---|
746 | |
---|
747 | function _display($text) |
---|
748 | { |
---|
749 | print $text; |
---|
750 | } |
---|
751 | } |
---|