Initial revision
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_tsparser.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2003 Kasper Skårhøj (kasper@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains the TypoScript parser class
29 *
30 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
31 *
32 * @author Kasper Skårhøj <kasper@typo3.com>
33 * @package TYPO3
34 * @subpackage t3lib
35 */
36 /**
37 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 79: class t3lib_TSparser
42 * 129: function parse($string,$matchObj='')
43 * 165: function nextDivider()
44 * 181: function parseSub(&$setup)
45 * 327: function rollParseSub($string,&$setup)
46 * 351: function getVal($string,$setup)
47 * 377: function setVal($string,&$setup,$value,$wipeOut=0)
48 * 412: function error($err,$num=2)
49 * 424: function checkIncludeLines($string)
50 * 468: function checkIncludeLines_array($array)
51 *
52 * SECTION: Syntax highlighting
53 * 511: function doSyntaxHighlight($string,$lineNum='',$highlightBlockMode=0)
54 * 532: function regHighLight($code,$pointer,$strlen=-1)
55 * 550: function syntaxHighlight_print($lineNumDat,$highlightBlockMode)
56 *
57 * TOTAL FUNCTIONS: 12
58 * (This index is automatically created/updated by the extension "extdeveval")
59 *
60 */
61
62
63
64
65
66
67
68
69
70
71
72
73 /**
74 * The TypoScript parser
75 *
76 * @author Kasper Skårhøj <kasper@typo3.com>
77 * @see t3lib_tstemplate, t3lib_matchcondition, t3lib_BEfunc::getPagesTSconfig(), t3lib_userAuthGroup::fetchGroupData(), t3lib_TStemplate::generateConfig()
78 */
79 class t3lib_TSparser {
80 var $strict = 1; // If set, then key names cannot contain characters other than [:alnum:]_\.-
81
82 // Internal
83 var $setup = Array(); // TypoScript hierarchy being build during parsing.
84 var $raw; // raw data, the input string exploded by chr(10)
85 var $rawP; // pointer to entry in raw data array
86 var $lastComment=''; // Holding the value of the last comment
87 var $commentSet=0; // Internally set, used as internal flag to create a multi-line comment (one of those like /*... */)
88 var $multiLineEnabled=0; // Internally set, when multiline value is accumulated
89 var $multiLineObject=''; // Internally set, when multiline value is accumulated
90 var $multiLineValue=array(); // Internally set, when multiline value is accumulated
91 var $inBrace = 0; // Internally set, when in brace. Counter.
92 var $lastConditionTrue = 1; // For each condition this flag is set, if the condition is true, else it's cleared. Then it's used by the [ELSE] condition to determine if the next part should be parsed.
93 var $sections=array(); // Tracking all conditions found
94 var $sectionsMatch=array(); // Tracking all matching conditions found
95 var $syntaxHighLight = 0; // If set, then syntax highlight mode is on; Call the function syntaxHighlight() to use this function
96 var $highLightData=array(); // Syntax highlight data is accumulated in this array. Used by syntaxHighlight_print() to construct the output.
97 var $highLightData_bracelevel = array(); // Syntax highlight data keeping track of the curly brace level for each line
98
99 // Debugging, analysis:
100 var $regComments = 0; // DO NOT register the comments. This is default for the ordinary sitetemplate!
101 var $errors=array(); // Error accumulation array.
102 var $lineNumberOffset=0; // Used for the error messages line number reporting. Set externally.
103 var $breakPointLN=0; // Line for break point.
104 var $highLightStyles=array(
105 'prespace' => array('<span class="ts-prespace">','</span>'), // Space before any content on a line
106 'objstr_postspace' => array('<span class="ts-objstr_postspace">','</span>'), // Space after the object string on a line
107 'operator_postspace' => array('<span class="ts-operator_postspace">','</span>'), // Space after the operator on a line
108 'operator' => array('<span class="ts-operator">','</span>'), // The operator char
109 'value' => array('<span class="ts-value">','</span>'), // The value of a line
110 'objstr' => array('<span class="ts-objstr">','</span>'), // The object string of a line
111 'value_copy' => array('<span class="ts-value_copy">','</span>'), // The value when the copy syntax (<) is used; that means the object reference
112 'value_unset' => array('<span class="ts-value_unset">','</span>'), // The value when an object is unset. Should not exist.
113 'ignored' => array('<span class="ts-ignored">','</span>'), // The "rest" of a line which will be ignored.
114 'default' => array('<span class="ts-default">','</span>'), // The default style if none other is applied.
115 'comment' => array('<span class="ts-comment">','</span>'), // Comment lines
116 'condition' => array('<span class="ts-condition">','</span>'), // Conditions
117 'error' => array('<span class="ts-error">','</span>'), // Error messages
118 'linenum' => array('<span class="ts-linenum">','</span>'), // Line numbers
119 );
120 var $highLightBlockStyles = ''; // Additional attributes for the <span> tags for a blockmode line
121 var $highLightBlockStyles_basecolor = '#cccccc'; // The hex-HTML color for the blockmode
122
123
124 /**
125 * Start parsing the input TypoScript text piece. The result is stored in $this->setup
126 *
127 * @param string The TypoScript text
128 * @param object If is object (instance of t3lib_matchcondition), then this is used to match conditions found in the TypoScript code. If matchObj not specified, then no conditions will work! (Except [GLOBAL])
129 * @return void
130 */
131 function parse($string,$matchObj='') {
132 $this->raw = explode(chr(10),$string);
133 $this->rawP = 0;
134
135 $pre = '[GLOBAL]';
136 while($pre) {
137 if ($this->breakPointLN && $pre=='[_BREAK]') {
138 $this->error('Breakpoint at '.($this->lineNumberOffset+$this->rawP-2).': Line content was "'.$this->raw[$this->rawP-2].'"',1);
139 break;
140 }
141
142 if (strtoupper($pre)=='[GLOBAL]' || strtoupper($pre)=='[END]' || (!$this->lastConditionTrue && strtoupper($pre)=='[ELSE]')) {
143 $pre = trim($this->parseSub($this->setup));
144 $this->lastConditionTrue=1;
145 } else {
146 if (strtoupper($pre)!='[ELSE]') {$this->sections[md5($pre)]=$pre;} // we're in a specific section. Therefore we log this section
147 if ((is_object($matchObj) && $matchObj->match($pre)) || $this->syntaxHighLight) {
148 if (strtoupper($pre)!='[ELSE]') {$this->sectionsMatch[md5($pre)]=$pre;}
149 $pre = trim($this->parseSub($this->setup));
150 $this->lastConditionTrue=1;
151 } else {
152 $pre = trim($this->nextDivider());
153 $this->lastConditionTrue=0;
154 }
155 }
156 }
157 if ($this->inBrace) {$this->error('Line '.($this->lineNumberOffset+$this->rawP-1).': The script is short of '.$this->inBrace.' end brace(s)',1); }
158 if ($this->multiLineEnabled) {$this->error('Line '.($this->lineNumberOffset+$this->rawP-1).': A multiline value section is not ended with a parenthesis!',1); }
159 $this->lineNumberOffset+=count($this->raw)+1;
160 }
161
162 /**
163 * Will search for the next condition. When found it will return the line content (the condition value) and have advanced the internal $this->rawP pointer to point to the next line after the condition.
164 *
165 * @return string The condition value
166 * @see parse()
167 */
168 function nextDivider() {
169 while (isset($this->raw[$this->rawP])) {
170 $line = ltrim($this->raw[$this->rawP]);
171 $this->rawP++;
172 if ($line && substr($line,0,1)=='[') {
173 return $line;
174 }
175 }
176 }
177
178 /**
179 * Parsing the $this->raw TypoScript lines from pointer, $this->rawP
180 *
181 * @param array Reference to the setup array in which to accumulate the values.
182 * @return string Returns the string of the condition found, the exit signal or possible nothing (if it completed parsing with no interruptions)
183 */
184 function parseSub(&$setup) {
185 while (isset($this->raw[$this->rawP])) {
186 $line = ltrim($this->raw[$this->rawP]);
187 $lineP = $this->rawP;
188 $this->rawP++;
189 if ($this->syntaxHighLight) $this->regHighLight("prespace",$lineP,strlen($line));
190
191 // Breakpoint?
192 if ($this->breakPointLN && ($this->lineNumberOffset+$this->rawP-1)==($this->breakPointLN+1)) { // by adding 1 we get that line processed
193 return '[_BREAK]';
194 }
195
196 // Set comment flag?
197 if (!$this->multiLineEnabled && substr($line,0,2)=='/*') {
198 $this->commentSet=1;
199 }
200
201 if (!$this->commentSet && ($line || $this->multiLineEnabled)) { // If $this->multiLineEnabled we will go and get the line values here because we know, the first if() will be true.
202 if ($this->multiLineEnabled) { // If multiline is enabled. Escape by ')'
203 if (substr($line,0,1)==')') { // Multiline ends...
204 if ($this->syntaxHighLight) $this->regHighLight("operator",$lineP,strlen($line)-1);
205 $this->multiLineEnabled=0; // Disable multiline
206 $theValue = implode($this->multiLineValue,chr(10));
207 if (strstr($this->multiLineObject,'.')) {
208 $this->setVal($this->multiLineObject,$setup,array($theValue)); // Set the value deeper.
209 } else {
210 $setup[$this->multiLineObject] = $theValue; // Set value regularly
211 if ($this->lastComment && $this->regComments) {
212 $setup[$this->multiLineObject.'..'].=$this->lastComment;
213 }
214 }
215 } else{
216 if ($this->syntaxHighLight) $this->regHighLight("value",$lineP);
217 $this->multiLineValue[]=$this->raw[($this->rawP-1)];
218 }
219 } elseif ($this->inBrace==0 && substr($line,0,1)=='[') { // Beginning of condition (only on level zero compared to brace-levels
220 if ($this->syntaxHighLight) $this->regHighLight("condition",$lineP);
221 return $line;
222 } else {
223 if (substr($line,0,1)=='[' && strtoupper(trim($line))=='[GLOBAL]') { // Return if GLOBAL condition is set - no matter what.
224 if ($this->syntaxHighLight) $this->regHighLight("condition",$lineP);
225 $this->error('Line '.($this->lineNumberOffset+$this->rawP-1).': On return to [GLOBAL] scope, the script was short of '.$this->inBrace.' end brace(s)',1);
226 $this->inBrace=0;
227 return $line;
228 } elseif (strcspn($line,'}#/')!=0) { // If not brace-end or comment
229 $varL = strcspn($line,' {=<>('); // Find object name string until we meet an operator VER2: Added '>'!!
230 $objStrName=trim(substr($line,0,$varL));
231 if ($this->syntaxHighLight) $this->regHighLight("objstr",$lineP,strlen(substr($line,$varL)));
232 if ($objStrName) {
233 if ($this->strict && eregi('[^[:alnum:]_\.-]',$objStrName,$r)) {
234 $this->error('Line '.($this->lineNumberOffset+$this->rawP-1).': Object Name String, "'.htmlspecialchars($objStrName).'" contains invalid character "'.$r[0].'". Must be alphanumeric or one of: "_-."');
235 } else {
236 $line = ltrim(substr($line,$varL));
237 if ($this->syntaxHighLight) {
238 $this->regHighLight("objstr_postspace", $lineP, strlen($line));
239 if (strlen($line)>0) {
240 $this->regHighLight("operator", $lineP, strlen($line)-1);
241 $this->regHighLight("operator_postspace", $lineP, strlen(ltrim(substr($line,1))));
242 }
243 }
244 switch(substr($line,0,1)) {
245 case '=':
246 if ($this->syntaxHighLight) $this->regHighLight("value", $lineP, strlen(ltrim(substr($line,1)))-strlen(trim(substr($line,1))));
247 if (strstr($objStrName,'.')) {
248 $value = Array();
249 $value[0] = trim(substr($line,1));
250 $this->setVal($objStrName,$setup,$value);
251 } else {
252 $setup[$objStrName] = trim(substr($line,1));
253 if ($this->lastComment && $this->regComments) { // Setting comment..
254 $setup[$objStrName.'..'].=$this->lastComment;
255 }
256 }
257 break;
258 case '{':
259 $this->inBrace++;
260 if (strstr($objStrName,'.')) {
261 $exitSig=$this->rollParseSub($objStrName,$setup);
262 if ($exitSig) return $exitSig;
263 } else {
264 if (!isset($setup[$objStrName.'.'])) {$setup[$objStrName.'.'] = Array();}
265 $exitSig=$this->parseSub($setup[$objStrName.'.']);
266 if ($exitSig) return $exitSig;
267 }
268 break;
269 case '(':
270 $this->multiLineObject = $objStrName;
271 $this->multiLineEnabled=1;
272 $this->multiLineValue=array();
273 break;
274 case '<':
275 if ($this->syntaxHighLight) $this->regHighLight("value_copy", $lineP, strlen(ltrim(substr($line,1)))-strlen(trim(substr($line,1))));
276 $theVal = trim(substr($line,1));
277 if (substr($theVal,0,1)=='.') {
278 $res = $this->getVal(substr($theVal,1),$setup);
279 } else {
280 $res = $this->getVal($theVal,$this->setup);
281 }
282 $this->setVal($objStrName,$setup,unserialize(serialize($res)),1);
283 break;
284 case '>':
285 if ($this->syntaxHighLight) $this->regHighLight("value_unset", $lineP, strlen(ltrim(substr($line,1)))-strlen(trim(substr($line,1))));
286 $this->setVal($objStrName,$setup,'UNSET');
287 break;
288 default:
289 $this->error('Line '.($this->lineNumberOffset+$this->rawP-1).': Object Name String, "'.htmlspecialchars($objStrName).'" was not preceeded by any operator, =<>({');
290 break;
291 }
292 }
293 $this->lastComment='';
294 }
295 } elseif (substr($line,0,1)=='}') {
296 $this->inBrace--;
297 $this->lastComment='';
298 if ($this->syntaxHighLight) $this->regHighLight("operator", $lineP, strlen($line)-1);
299 if ($this->inBrace<0) {
300 $this->error('Line '.($this->lineNumberOffset+$this->rawP-1).': An end brace is in excess.',1);
301 $this->inBrace=0;
302 } else {
303 break;
304 }
305 } else {
306 if ($this->syntaxHighLight) $this->regHighLight("comment", $lineP);
307
308 // Comment. The comments are concatenated in this temporary string:
309 if ($this->regComments) $this->lastComment.= trim($line).chr(10);
310 }
311 }
312 }
313
314 // Unset comment
315 if ($this->commentSet) {
316 if ($this->syntaxHighLight) $this->regHighLight("comment", $lineP);
317 if (substr($line,0,2)=='*/') $this->commentSet=0;
318 }
319 }
320 }
321
322 /**
323 * Parsing of TypoScript keys inside a curly brace where the key is composite of at least two keys, thus having to recursively call itself to get the value
324 *
325 * @param string The object sub-path, eg "thisprop.another_prot"
326 * @param array The local setup array from the function calling this function
327 * @return string Returns the exitSignal
328 * @see parseSub()
329 */
330 function rollParseSub($string,&$setup) {
331 if ((string)$string!='') {
332 $keyLen = strcspn($string,'.');
333 if ($keyLen==strlen($string)) {
334 $key = $string.'.';
335 if (!isset($setup[$key])){$setup[$key]=Array();}
336 $exitSig=$this->parseSub($setup[$key]);
337 if ($exitSig) return $exitSig;
338 } else {
339 $key = substr($string,0,$keyLen).'.';
340 if (!isset($setup[$key])){$setup[$key]=Array();}
341 $exitSig=$this->rollParseSub(substr($string,$keyLen+1),$setup[$key]);
342 if ($exitSig) return $exitSig;
343 }
344 }
345 }
346
347 /**
348 * Get a value/property pair for an object path in TypoScript, eg. "myobject.myvalue.mysubproperty". Here: Used by the "copy" operator, <
349 *
350 * @param string Object path for which to get the value
351 * @param array Global setup code if $string points to a global object path. But if string is prefixed with "." then its the local setup array.
352 * @return array An array with keys 0/1 being value/property respectively
353 */
354 function getVal($string,$setup) {
355 if ((string)$string!='') {
356 $keyLen = strcspn($string,'.');
357 if ($keyLen==strlen($string)) {
358 $retArr=array(); // Added 6/6/03. Shouldn't hurt
359 if (isset($setup[$string])) {$retArr[0]=$setup[$string]; }
360 if (isset($setup[$string.'.'])) {$retArr[1]=$setup[$string.'.']; }
361 return $retArr;
362 } else {
363 $key = substr($string,0,$keyLen).'.';
364 if ($setup[$key]) {
365 return $this->getVal(substr($string,$keyLen+1),$setup[$key]);
366 }
367 }
368 }
369 }
370
371 /**
372 * Setting a value/property of an object string in the setup array.
373 *
374 * @param string The object sub-path, eg "thisprop.another_prot"
375 * @param array The local setup array from the function calling this function.
376 * @param array The value/property pair array to set. If only one of them is set, then the other is not touched (unless $wipeOut is set, which it is when copies are made which must include both value and property)
377 * @param boolean If set, then both value and property is wiped out when a copy is made of another value.
378 * @return void
379 */
380 function setVal($string,&$setup,$value,$wipeOut=0) {
381 if ((string)$string!='') {
382 $keyLen = strcspn($string,'.');
383 if ($keyLen==strlen($string)) {
384 if ($value=='UNSET') {
385 unset($setup[$string]);
386 unset($setup[$string.'.']);
387 } else {
388 if ($wipeOut && $this->strict) {
389 if ((isset($setup[$string]) && !isset($value[0])) || (isset($setup[$string.'.']) && !isset($value[1]))) {$this->error('Line '.($this->lineNumberOffset+$this->rawP-1).': Object copied in this line "'.trim($this->raw[($this->rawP-1)]).'" would leave either the value or properties untouched in TypoScript Version 1. Please check that this is not a problem for you.',1);}
390 unset($setup[$string]);
391 unset($setup[$string.'.']);
392 }
393 if (isset($value[0])) {$setup[$string] = $value[0];}
394 if (isset($value[1])) {$setup[$string.'.'] = $value[1];}
395 if ($this->lastComment && $this->regComments) {
396 $setup[$string.'..'].=$this->lastComment;
397 }
398 }
399 } else {
400 $key = substr($string,0,$keyLen).'.';
401 if (!isset($setup[$key])){$setup[$key]=Array();}
402 $this->setVal(substr($string,$keyLen+1),$setup[$key],$value);
403 }
404 }
405 }
406
407 /**
408 * Stacks errors/messages from the TypoScript parser into an internal array, $this->error
409 * If "TT" is a global object (as it is in the frontend when backend users are logged in) the message will be registered here as well.
410 *
411 * @param string The error message string
412 * @param integer The error severity (in the scale of $GLOBALS['TT']->setTSlogMessage: Approx: 2=warning, 1=info, 0=nothing, 3=fatal.)
413 * @return void
414 */
415 function error($err,$num=2) {
416 if (is_object($GLOBALS['TT'])) $GLOBALS['TT']->setTSlogMessage($err,$num);
417 $this->errors[]=array($err,$num,$this->rawP-1,$this->lineNumberOffset);
418 }
419
420 /**
421 * Checks the input string (un-parsed TypoScript) for include-commands ("<INCLUDE_TYPOSCRIPT: ....")
422 * Use: t3lib_TSparser::checkIncludeLines()
423 *
424 * @param string Unparsed TypoScript
425 * @return string Complete TypoScript with includes added.
426 */
427 function checkIncludeLines($string) {
428 $splitStr='<INCLUDE_TYPOSCRIPT:';
429 if (strstr($string,$splitStr)) {
430 $newString='';
431 $allParts = explode($splitStr,chr(10).$string.chr(10)); // adds line break char before/after
432 reset($allParts);
433 while(list($c,$v)=each($allParts)) {
434 if (!$c) { // first goes through
435 $newString.=$v;
436 } elseif (ereg("\r?\n[ ]*$",$allParts[$c-1])) { // There must be a line-break char before.
437 $subparts=explode('>',$v,2);
438 if (ereg("^[ ]*\r?\n",$subparts[1])) { // There must be a line-break char after
439 // SO, the include was positively recognized:
440 $newString.='### '.$splitStr.$subparts[0].'> BEGIN:'.chr(10);
441 $params = t3lib_div::get_tag_attributes($subparts[0]);
442 if ($params['source']) {
443 $sourceParts = explode(':',$params['source'],2);
444 switch(strtolower(trim($sourceParts[0]))) {
445 case 'file':
446 $filename = t3lib_div::getFileAbsFileName(trim($sourceParts[1]));
447 if (strcmp($filename,'')) { // Must exist and must not contain '..' and must be relative
448 if (@is_file($filename) && filesize($filename)<100000) { // Max. 100 KB include files!
449 $newString.=t3lib_div::getUrl($filename).chr(10);
450 }
451 }
452 break;
453 }
454 }
455 $newString.='### '.$splitStr.$subparts[0].'> END:'.chr(10);
456 $newString.=$subparts[1];
457 } else $newString.=$splitStr.$v;
458 } else $newString.=$splitStr.$v;
459 }
460 $string=substr($newString,1,-1); // not the first/last linebreak char.
461 }
462 return $string;
463 }
464
465 /**
466 * Parses the string in each value of the input array for include-commands
467 *
468 * @param array Array with TypoScript in each value
469 * @return array Same array but where the values has been parsed for include-commands
470 */
471 function checkIncludeLines_array($array) {
472 reset($array);
473 while(list($k)=each($array)) {
474 $array[$k]=t3lib_TSparser::checkIncludeLines($array[$k]);
475 }
476 return $array;
477 }
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499 /**********************************
500 *
501 * Syntax highlighting
502 *
503 *********************************/
504
505 /**
506 * Syntax highlight a TypoScript text
507 * Will parse the content. Remember, the internal setup array may contain INvalid parsed content since conditions are ignored!
508 *
509 * @param string The TypoScript text
510 * @param mixed If blank, linenumbers are NOT printed. If array then the first key is the linenumber offset to add to the internal counter.
511 * @param boolean If set, then the highlighted output will be formatted in blocks based on the brace levels. prespace will be ignored and empty lines represented with a single no-break-space.
512 * @return string HTML code for the syntax highlighted string
513 */
514 function doSyntaxHighlight($string,$lineNum='',$highlightBlockMode=0) {
515 $this->syntaxHighLight=1;
516 $this->highLightData=array();
517 $this->error=array();
518 $string = str_replace(chr(13),'',$string); // This is done in order to prevent empty <span>..</span> sections around chr(13) content. Should not do anything but help lessen the amount of HTML code.
519
520 $this->parse($string);
521
522 return $this->syntaxHighlight_print($lineNum,$highlightBlockMode);
523 }
524
525 /**
526 * Registers a part of a TypoScript line for syntax highlighting.
527 *
528 * @param string Key from the internal array $this->highLightStyles
529 * @param integer Pointer to the line in $this->raw which this is about
530 * @param integer The number of chars LEFT on this line before the end is reached.
531 * @return void
532 * @access private
533 * @see parse()
534 */
535 function regHighLight($code,$pointer,$strlen=-1) {
536 if ($strlen==-1) {
537 $this->highLightData[$pointer] = array(array($code,0));
538 } else {
539 $this->highLightData[$pointer][] = array($code,$strlen);
540 }
541 $this->highLightData_bracelevel[$pointer] = $this->inBrace;
542 }
543
544 /**
545 * Formatting the TypoScript code in $this->raw based on the data collected by $this->regHighLight in $this->highLightData
546 *
547 * @param mixed If blank, linenumbers are NOT printed. If array then the first key is the linenumber offset to add to the internal counter.
548 * @param boolean If set, then the highlighted output will be formatted in blocks based on the brace levels. prespace will be ignored and empty lines represented with a single no-break-space.
549 * @return string HTML content
550 * @access private
551 * @see doSyntaxHighlight()
552 */
553 function syntaxHighlight_print($lineNumDat,$highlightBlockMode) {
554 // Registers all error messages in relation to their linenumber
555 $errA=array();
556 foreach($this->errors as $err) {
557 $errA[$err[2]][]=$err[0];
558 }
559 // Generates the syntax highlighted output:
560 $lines=array();
561 foreach($this->raw as $rawP => $value) {
562 $start=0;
563 $strlen=strlen($value);
564 $lineC='';
565
566 if (is_array($this->highLightData[$rawP])) {
567 foreach($this->highLightData[$rawP] as $set) {
568 $len = $strlen-$start-$set[1];
569 if ($len > 0) {
570 $part = substr($value,$start,$len);
571 $start+=$len;
572 $st = $this->highLightStyles[(isset($this->highLightStyles[$set[0]])?$set[0]:'default')];
573 if (!$highlightBlockMode || $set[0]!='prespace') $lineC.=$st[0].htmlspecialchars($part).$st[1];
574 }elseif ($len < 0) debug(array($len,$value,$rawP));
575 }
576 } else debug(array($value));
577
578 if (strlen(substr($value,$start))) $lineC.=$this->highLightStyles['ignored'][0].htmlspecialchars(substr($value,$start)).$this->highLightStyles['ignored'][1];
579
580 if ($errA[$rawP]) {
581 # $lineC.=$this->highLightStyles['error'][0].htmlspecialchars(trim(substr($value,$start))).$this->highLightStyles['error'][1].
582 # $start=strlen($value);
583 $lineC.=$this->highLightStyles['error'][0].'<strong> - ERROR:</strong> '.htmlspecialchars(implode(';',$errA[$rawP])).$this->highLightStyles['error'][1];
584 }
585
586 if ($highlightBlockMode && $this->highLightData_bracelevel[$rawP]) {
587 $lineC = str_pad('',$this->highLightData_bracelevel[$rawP]*2,' ',STR_PAD_LEFT).'<span style="'.$this->highLightBlockStyles.($this->highLightBlockStyles_basecolor?'background-color: '.t3lib_div::modifyHTMLColorAll($this->highLightBlockStyles_basecolor,-$this->highLightData_bracelevel[$rawP]*16):'').'">'.(strcmp($lineC,'')?$lineC:'&nbsp;').'</span>';
588 }
589
590 if (is_array($lineNumDat)) {
591 $lineNum = $rawP+$lineNumDat[0];
592 $lineC = $this->highLightStyles['linenum'][0].str_pad($lineNum,4,' ',STR_PAD_LEFT).':'.$this->highLightStyles['linenum'][1].' '.$lineC;
593 }
594
595
596 $lines[] = $lineC;
597 }
598
599 return '<pre class="ts-hl">'.implode(chr(10),$lines).'</pre>';
600 }
601
602
603 /*
604 function xmlToTypoScriptStruct($xmlInput) {
605 $res = t3lib_div::xml2tree($xmlInput);
606 if (is_array($res)) {
607 $this->xmlToTypoScriptSetup($res);
608 } else return 'XML parser error: '.$res;
609 }
610 */
611 }
612
613
614 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tsparser.php']) {
615 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tsparser.php']);
616 }
617 ?>